在MATLAB版本7中相当于pdist2
我需要计算matlab中2个matrix之间的欧式距离。 目前我使用bsxfun和计算距离如下(我附上一段代码):
for i=1:4754 test_data=fea_test(i,:); d=sqrt(sum(bsxfun(@minus, test_data, fea_train).^2, 2)); end
fea_test的大小是4754×1024,fea_train是6800×1024,使用for循环导致执行for花了大约12分钟,我认为这太高了。 有没有办法计算两个matrix之间的欧氏距离更快?
我被告知,通过删除不必要的循环,我可以减less执行时间。 我也知道,pdist2可以帮助减less计算时间,但是因为我使用的是matlab版本7,所以没有pdist2函数。 升级不是一个选项。
任何帮助。
问候,
巴维亚
您可以通过重复fea_test 6800次和fea_train 4754次的行来完全vector化计算,如下所示:
rA = size(fea_test,1); rB = size(fea_train,1); [I,J]=ndgrid(1:rA,1:rB); d = zeros(rA,rB); d(:) = sqrt(sum(fea_test(J(:),:)-fea_train(I(:),:)).^2,2));
但是,这将导致大小为6800x4754x1024(* 8字节的中间数组),这将占用大约250GB的RAM。 因此,完整的vector化将不起作用。
但是,可以通过预分配减less距离计算的时间,并且在必要之前不计算平方根:
rA = size(fea_test,1); rB = size(fea_train,1); d = zeros(rA,rB); for i = 1:rA test_data=fea_test(i,:); d(i,:)=sum( (test_data(ones(nB,1),:) - fea_train).^2, 2))'; end d = sqrt(d);
这里是计算欧几里德距离的vector化实现,比你所拥有的要快得多(甚至比我的机器上的PDIST2快得多):
D = sqrt( bsxfun(@plus,sum(A.^2,2),sum(B.^2,2)') - 2*(A*B') );
它基于以下事实: ||uv||^2 = ||u||^2 + ||v||^2 - 2*uv
下面考虑两种方法之间的粗略比较:
A = rand(4754,1024); B = rand(6800,1024); tic D = pdist2(A,B,'euclidean'); toc tic DD = sqrt( bsxfun(@plus,sum(A.^2,2),sum(B.^2,2)') - 2*(A*B') ); toc
在运行R2011b的WinXP笔记本电脑上,我们可以看到10倍的时间改进:
Elapsed time is 70.939146 seconds. %# PDIST2 Elapsed time is 7.879438 seconds. %# vectorized solution
你应该知道,它并没有给出与PDIST2 完全相同的结果,直到最小的精度。通过比较结果,你会看到很小的差异(通常接近eps的浮点相对精度):
>> max( abs(D(:)-DD(:)) ) ans = 1.0658e-013
在一个侧面说明中,我收集了大约10个不同的实现(有些只是彼此的小变化),这个距离计算,并一直在比较它们。 与其他vector化解决scheme相比,您会惊讶地发现简单循环的速度有多快(感谢JIT)。
试试这个vector化版本,它应该是非常有效的。 编辑:只是注意到,我的答案是类似于@ Amro的。
function K = calculateEuclideanDist(P,Q) % Vectorized method to compute pairwise Euclidean distance % Returns K(i,j) = sqrt((P(i,:) - Q(j,:))'*(P(i,:) - Q(j,:))) [nP, d] = size(P); [nQ, d] = size(Q); pmag = sum(P .* P, 2); qmag = sum(Q .* Q, 2); K = sqrt(ones(nP,1)*qmag' + pmag*ones(1,nQ) - 2*P*Q'); end