Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/matlab/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Performance 在Matlab中高效计算两两平方欧氏距离_Performance_Matlab_Matrix_Distance_Euclidean Distance - Fatal编程技术网

Performance 在Matlab中高效计算两两平方欧氏距离

Performance 在Matlab中高效计算两两平方欧氏距离,performance,matlab,matrix,distance,euclidean-distance,Performance,Matlab,Matrix,Distance,Euclidean Distance,给定两组d维点。如何在Matlab中最有效地计算成对平方欧氏距离矩阵 表示法: 集合一由a(numA,d)-matrixa给出,集合二由a(numB,d)-matrixB给出。结果距离矩阵的格式应为(numA,numB) 示例要点: d = 4; % dimension numA = 100; % number of set 1 points numB = 200; % number of set 2 points A = rand(numA,d);

给定两组
d
维点。如何在Matlab中最有效地计算成对平方欧氏距离矩阵

表示法: 集合一由a
(numA,d)
-matrix
a
给出,集合二由a
(numB,d)
-matrix
B
给出。结果距离矩阵的格式应为
(numA,numB)

示例要点:

d = 4;            % dimension
numA = 100;       % number of set 1 points
numB = 200;       % number of set 2 points
A = rand(numA,d); % set 1 given as matrix A
B = rand(numB,d); % set 2 given as matrix B
%% create some points
d = 2; % dimension
numA = 20000;
numB = 20000;
A = rand(numA,d);
B = rand(numB,d);

%% pairwise distance matrix
% proposed method:
tic;
helpA = zeros(numA,3*d);
helpB = zeros(numB,3*d);
for idx = 1:d
    helpA(:,3*idx-2:3*idx) = [ones(numA,1), -2*A(:,idx), A(:,idx).^2 ];
    helpB(:,3*idx-2:3*idx) = [B(:,idx).^2 ,    B(:,idx), ones(numB,1)];
end
distMat = helpA * helpB';
toc;

% compare to pdist2:
tic;
pdist2(A,B).^2;
toc;

% compare to [1]:
tic;
bsxfun(@plus,dot(A,A,2),dot(B,B,2)')-2*(A*B');
toc;

% Another method: added 07/2014
% compare to ndgrid method (cf. Dan's comment)
tic;
[idxA,idxB] = ndgrid(1:numA,1:numB);
distMat = zeros(numA,numB);
distMat(:) = sum((A(idxA,:) - B(idxB,:)).^2,2);
toc;

这里通常给出的答案基于
bsxfun
(参见示例)。我提出的方法基于矩阵乘法,结果证明比我能找到的任何类似算法都快得多:

helpA = zeros(numA,3*d);
helpB = zeros(numB,3*d);
for idx = 1:d
    helpA(:,3*idx-2:3*idx) = [ones(numA,1), -2*A(:,idx), A(:,idx).^2 ];
    helpB(:,3*idx-2:3*idx) = [B(:,idx).^2 ,    B(:,idx), ones(numB,1)];
end
distMat = helpA * helpB';
请注意: 对于常量
d
,可以用硬编码实现代替
For
-循环,例如:

helpA(:,3*idx-2:3*idx) = [ones(numA,1), -2*A(:,1), A(:,1).^2, ... % d == 2
                          ones(numA,1), -2*A(:,2), A(:,2).^2 ];   % etc.
评估:

d = 4;            % dimension
numA = 100;       % number of set 1 points
numB = 200;       % number of set 2 points
A = rand(numA,d); % set 1 given as matrix A
B = rand(numB,d); % set 2 given as matrix B
%% create some points
d = 2; % dimension
numA = 20000;
numB = 20000;
A = rand(numA,d);
B = rand(numB,d);

%% pairwise distance matrix
% proposed method:
tic;
helpA = zeros(numA,3*d);
helpB = zeros(numB,3*d);
for idx = 1:d
    helpA(:,3*idx-2:3*idx) = [ones(numA,1), -2*A(:,idx), A(:,idx).^2 ];
    helpB(:,3*idx-2:3*idx) = [B(:,idx).^2 ,    B(:,idx), ones(numB,1)];
end
distMat = helpA * helpB';
toc;

% compare to pdist2:
tic;
pdist2(A,B).^2;
toc;

% compare to [1]:
tic;
bsxfun(@plus,dot(A,A,2),dot(B,B,2)')-2*(A*B');
toc;

% Another method: added 07/2014
% compare to ndgrid method (cf. Dan's comment)
tic;
[idxA,idxB] = ndgrid(1:numA,1:numB);
distMat = zeros(numA,numB);
distMat(:) = sum((A(idxA,:) - B(idxB,:)).^2,2);
toc;
结果:

Elapsed time is 1.796201 seconds.
Elapsed time is 5.653246 seconds.
Elapsed time is 3.551636 seconds.
Elapsed time is 22.461185 seconds.
有关更详细的评估,请参见以下讨论(@comments)。事实证明,在不同的设置下,应该首选不同的算法。在非时间紧急情况下,只需使用
pdist2
版本

进一步发展: 基于相同的原理,可以考虑用任何其他度量替换平方欧几里德:

help = zeros(numA,numB,d);
for idx = 1:d
    help(:,:,idx) = [ones(numA,1), A(:,idx)     ] * ...
                    [B(:,idx)'   ; -ones(1,numB)];
end
distMat = sum(ANYFUNCTION(help),3);
然而,这是相当耗时的。用
d
2维矩阵替换较小的
d
三维矩阵
help
,可能会很有用。特别是对于
d=1
,它提供了一种通过简单的矩阵乘法计算成对差的方法:

pairDiffs = [ones(numA,1), A ] * [B'; -ones(1,numB)];

你还有什么想法吗?

对于平方欧几里德距离,也可以使用以下公式

||a-b||^2 = ||a||^2 + ||b||^2 - 2<a,b>

最近,我发现,从R2016b开始,这种计算平方欧几里德距离的方法比公认的方法要快。

你看过
pdist2
函数了吗@是的,请看一下我答案中的评估部分:)真的很有趣+1在另一个故事中:在我大约从
d>30开始的机器上,
bsxfun
由于内存开销较低,将再次获胜。@knedlsepp感谢您花时间将所有这些放在一起!我确实再次对这两个矢量化版本进行了基准测试——这里提出的基于循环的版本,我没有看到太大的差异,至少对于小尺寸到合适尺寸的
dims
@Divakar:as在我的机器上:如果我们想要平方距离,在被
bsxfun
击败之前,您的
Vec1
版本在低维方面是最快的。如果我们想要实际的
sqrt
-距离
pdist2
更快,直到它最终也被
bsxfun
击败。在做了所有这些比较之后:我想,尽管很高兴知道我们可以从所有这些中挤出最后一点速度,但我不知何故感到,如果你安装了统计工具箱,简单地使用
pdist2
是一件很容易的事,因为它很灵活,但仍然非常快。@knedlsepp非常感谢-这是一个非常有趣的评估!我只想补充一点,log10中的时间尺度有点误导,因为计算时间的相关性并不存在于对数尺度上(例如,因子2对于节省时间来说非常有趣,但在log10尺度上看起来什么都不像)。我的facit:为一个时间关键的实现测试不同的算法是值得的(尤其是对于大量的点)。例如,对于大量2d数据点,使用我的实现是非常有用的。我真的很喜欢我们的algos系列!:)@Divakar您的矢量化变体是矩阵方法的有趣变体!竖起大拇指:)