繁体   English   中英

在Matlab中有效地计算成对平方欧几里德距离

[英]Efficiently compute pairwise squared Euclidean distance in Matlab

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

符号:第一组由(numA,d) A给出,第二组由(numB,d) 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

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

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.

评估:

%% 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 3 维矩阵help可能很有用。 特别是对于d = 1它提供了一种通过简单矩阵乘法计算成对差异的方法:

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

你还有什么想法吗?

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

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

其中<a,b>ab之间的点积

nA = sum( A.^2, 2 ); %// norm of A's elements
nB = sum( B.^2, 2 ); %// norm of B's elements
distMat = bsxfun( @plus, nA, nB' ) - 2 * A * B' ;

最近,有人告诉我,从 R2016b 开始,这种计算平方欧几里德距离的方法比公认的方法快。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM