通常给出的答案是基于
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, ...
ones(numA,1), -2*A(:,2), A(:,2).^2 ];
评估:
d = 2;
numA = 20000;
numB = 20000;
A = rand(numA,d);
B = rand(numB,d);
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;
tic;
pdist2(A,B).^2;
toc;
tic;
bsxfun(@plus,dot(A,A,2),dot(B,B,2)')-2*(A*B');
toc;
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);
然而,这样做非常耗时。将 3 维矩阵 help
替换为 d
个 2 维矩阵可能会很有用,特别是对于较小的 d
。特别是当 d = 1
时,可以通过简单的矩阵乘法计算成对差异。
pairDiffs = [ones(numA,1), A ] * [B'; -ones(1,numB)];
你有其他的想法吗?
pdist2
函数吗?http://www.mathworks.com/help/stats/pdist2.html - rayryeng