MATLAB 中的有效元素差异
Efficient elementwise differences in MATLAB
目前有一个 bunch of 关于在 MATLAB 中有效计算成对距离的方法(有些甚至是我做的!)。我想做些不同的事情。
而不是计算两个矩阵中行对之间的总距离,比如 X
和 Y
:
X = [1 1 1; 2 2 2];
Y = [1 2 3; 4 5 6];
我想计算一个 3 维矩阵,存储每对行之间的原始列差异。在上面的示例中,此矩阵将有两行(对于 X 中的 2 个观察值)、3 列和第 3 维中的 2 个切片(对于 Y 中的 2 个观察值):
diffs(:,:,1) =
0 -1 -2
1 0 -1
diffs(:,:,2) =
-3 -4 -5
-2 -3 -4
到目前为止,我已经提出了两种一般情况下的方法来完成此操作,但我想找到优雅、透明和高效的方法。
Repmat+Permute 方法
% Set up data
X = rand(100,10);
Y = rand(200,10);
timer = tic;
X_tiled = repmat(X,[1 1 size(Y,1)]);
Y_tiled = repmat(permute(Y,[3,2,1]),[size(X,1),1,1]);
diffs = X_tiled - Y_tiled;
toc(timer)
% Elapsed time is 0.001883 seconds.
For 循环方法
timer = tic;
diffs = zeros(size(X,1),size(X,2),size(Y,1));
for i = 1:size(X,1)
for j =1:size(Y,1)
diffs(i,:,j) = X(i,:) - Y(j,:);
end
end
toc(timer)
% Elapsed time is 0.028620 seconds.
有没有人有比我更好的东西?
在 Y
上使用 permute
将第一个维度发送到第三个位置后,您可以使用 bsxfun
将混乱的 repmat
替换为 under-the-hood broadcasting
将第二维保留在其位置以与 X
的第二维匹配。这可以通过 permute(Y,[3 2 1]
来实现。因此,解决方案是 -
diffs = bsxfun(@minus,X,permute(Y,[3 2 1]))
基准测试
基准代码-
% Set up data
X = rand(100,10);
Y = rand(200,10);
% Setup number of iterations
num_iter = 500;
%// Warm up tic/toc.
for iter = 1:50000
tic(); elapsed = toc();
end
disp('---------------- With messy REPMAT')
timer = tic;
for itr = 1:num_iter
X_tiled = repmat(X,[1 1 size(Y,1)]);
Y_tiled = repmat(permute(Y,[3,2,1]),[size(X,1),1,1]);
diffs = X_tiled - Y_tiled;
end
toc(timer)
disp('---------------- With sassy BSXFUN')
timer = tic;
for itr = 1:num_iter
diffs1 = bsxfun(@minus,X,permute(Y,[3 2 1]));
end
toc(timer)
输出-
---------------- With messy REPMAT
Elapsed time is 3.347060 seconds.
---------------- With sassy BSXFUN
Elapsed time is 0.966760 seconds.
目前有一个 bunch of
而不是计算两个矩阵中行对之间的总距离,比如 X
和 Y
:
X = [1 1 1; 2 2 2];
Y = [1 2 3; 4 5 6];
我想计算一个 3 维矩阵,存储每对行之间的原始列差异。在上面的示例中,此矩阵将有两行(对于 X 中的 2 个观察值)、3 列和第 3 维中的 2 个切片(对于 Y 中的 2 个观察值):
diffs(:,:,1) =
0 -1 -2
1 0 -1
diffs(:,:,2) =
-3 -4 -5
-2 -3 -4
到目前为止,我已经提出了两种一般情况下的方法来完成此操作,但我想找到优雅、透明和高效的方法。
Repmat+Permute 方法
% Set up data
X = rand(100,10);
Y = rand(200,10);
timer = tic;
X_tiled = repmat(X,[1 1 size(Y,1)]);
Y_tiled = repmat(permute(Y,[3,2,1]),[size(X,1),1,1]);
diffs = X_tiled - Y_tiled;
toc(timer)
% Elapsed time is 0.001883 seconds.
For 循环方法
timer = tic;
diffs = zeros(size(X,1),size(X,2),size(Y,1));
for i = 1:size(X,1)
for j =1:size(Y,1)
diffs(i,:,j) = X(i,:) - Y(j,:);
end
end
toc(timer)
% Elapsed time is 0.028620 seconds.
有没有人有比我更好的东西?
在 Y
上使用 permute
将第一个维度发送到第三个位置后,您可以使用 bsxfun
将混乱的 repmat
替换为 under-the-hood broadcasting
将第二维保留在其位置以与 X
的第二维匹配。这可以通过 permute(Y,[3 2 1]
来实现。因此,解决方案是 -
diffs = bsxfun(@minus,X,permute(Y,[3 2 1]))
基准测试
基准代码-
% Set up data
X = rand(100,10);
Y = rand(200,10);
% Setup number of iterations
num_iter = 500;
%// Warm up tic/toc.
for iter = 1:50000
tic(); elapsed = toc();
end
disp('---------------- With messy REPMAT')
timer = tic;
for itr = 1:num_iter
X_tiled = repmat(X,[1 1 size(Y,1)]);
Y_tiled = repmat(permute(Y,[3,2,1]),[size(X,1),1,1]);
diffs = X_tiled - Y_tiled;
end
toc(timer)
disp('---------------- With sassy BSXFUN')
timer = tic;
for itr = 1:num_iter
diffs1 = bsxfun(@minus,X,permute(Y,[3 2 1]));
end
toc(timer)
输出-
---------------- With messy REPMAT
Elapsed time is 3.347060 seconds.
---------------- With sassy BSXFUN
Elapsed time is 0.966760 seconds.