我正在MATLAB中计算基于欧几里得距离的相似矩阵。我的代码如下:
for i=1:N % M,N is the size of the matrix x for whose elements I am computing similarity matrix
for j=1:N
D(i,j) = sqrt(sum(x(:,i)-x(:,j)).^2)); % D is the similarity matrix
end
end
我的矩阵x
的维数是256x30000
,我能帮我优化这个=减少for循环吗?
非常感谢!
——Aditya
在matlab中执行此操作的函数称为pdist。不幸的是,它非常慢,并且没有考虑到matlab的矢量化能力。
下面是我为一个项目写的代码。让我知道你得到了什么样的加速。
Qx=repmat(dot(x,x,2),1,size(x,1));
D=sqrt(Qx+Qx'-2*x*x');
请注意,只有当数据点在行中,维度在列中时,这才有效。例如,假设我有256个数据点和100000个维度,然后在我的mac上使用x=rand(256,100000),上面的代码在大约半秒内生成一个256x256的矩阵。
可能有更好的方法来做到这一点,但我注意到的第一件事是,你可以通过利用对称性D(i,j)==D(i,j)
您也可以使用norm(x(:,i)-x(:,j),2)
我想这就是你要找的。
D=zeros(N);
jIndx=repmat(1:N,N,1);iIndx=jIndx'; %'# fix SO's syntax highlighting
D(:)=sqrt(sum((x(iIndx(:),:)-x(jIndx(:),:)).^2,2));
在这里,我假设距离向量x
被初始化为NxM
数组,其中M
是系统的维数,N
是点的数量。因此,如果您的排序不同,则必须进行相应的更改。
首先,您计算的量是这里需要的两倍,因为D将是对称的。你不需要分别计算(i,j)项和(j,i)项。将内循环更改为for j=1:i
,并在循环体中添加D(j,i)=D(i,j);
之后,这段代码所做的事情真的没有太多冗余,所以你唯一剩下的改进空间就是并行化它:如果你有并行计算工具箱,将你的外部循环转换为parfor
,在运行它之前,说matlabpool(n)
,其中n
是要使用的线程数。