我有一个n x p矩阵 - mX,它由R ^ p中的n个点组成。
我有另一个m x p矩阵 - mY,它由R ^ p中的m个参考点组成。
我想创建一个n x m矩阵 - mD,它是Mahalanobis Distance矩阵。
D(i,j)表示mX中的点i之间的Mahalanobis Distance,mX(i,:)和mY中的点j,mY(j,:)。
即,计算以下内容:
mD(i, j) = (mX(i, :) - mY(j, :)) * inv(mC) * (mX(i, :) - mY(j, :)).';
其中mC是给定的Mahalanobis距离PSD矩阵。
在循环中很容易完成,有没有办法对其进行矢量化?
即,是一个函数,它的输入是mX,mY和mC,它的输出是mD并且完全矢量化而不使用任何MATLAB工具箱?
谢谢。
答案 0 :(得分:1)
这是一个消除一个循环的解决方案
function d = mahalanobis(mX, mY)
n = size(mX, 2);
m = size(mY, 2);
data = [mX, mY];
mc = cov(transpose(data));
dist = zeros(n,m);
for i = 1 : n
diff = repmat(mX(:,i), 1, m) - mY;
dist(i,:) = sum((mc\diff).*diff , 1);
end
d = sqrt(dist);
end
您可以将其调用为:
d = mahalanobis(transpose(X),transpose(Y))
答案 1 :(得分:1)
方法#1
假设无限资源,这是使用bsxfun
和matrix-multiplication
的一个矢量化解决方案 -
A = reshape(bsxfun(@minus,permute(mX,[1 3 2]),permute(mY,[3 1 2])),[],p);
out = reshape(diag(A*inv(mC)*A.'),n,m);
方法#2
这是一个试图降低循环复杂度的解决方案 -
A = reshape(bsxfun(@minus,permute(mX,[1 3 2]),permute(mY,[3 1 2])),[],p);
imC = inv(mC);
out = zeros(n*m,1);
for ii = 1:n*m
out(ii) = A(ii,:)*imC*A(ii,:).';
end
out = reshape(out,n,m);
示例运行 -
>> n = 3; m = 4; p = 5;
mX = rand(n,p);
mY = rand(m,p);
mC = rand(p,p);
imC = inv(mC);
>> %// Original solution
for i = 1:n
for j = 1:m
mD(i, j) = (mX(i, :) - mY(j, :)) * inv(mC) * (mX(i, :) - mY(j, :)).'; %//'
end
end
>> mD
mD =
-8.4256 10.032 2.8929 7.1762
-44.748 -4.3851 -13.645 -9.6702
-4.5297 3.2928 0.11132 2.5998
>> %// Approach #1
A = reshape(bsxfun(@minus,permute(mX,[1 3 2]),permute(mY,[3 1 2])),[],p);
out = reshape(diag(A*inv(mC)*A.'),n,m); %//'
>> out
out =
-8.4256 10.032 2.8929 7.1762
-44.748 -4.3851 -13.645 -9.6702
-4.5297 3.2928 0.11132 2.5998
>> %// Approach #2
A = reshape(bsxfun(@minus,permute(mX,[1 3 2]),permute(mY,[3 1 2])),[],p);
imC = inv(mC);
out1 = zeros(n*m,1);
for ii = 1:n*m
out1(ii) = A(ii,:)*imC*A(ii,:).'; %//'
end
out1 = reshape(out1,n,m);
>> out1
out1 =
-8.4256 10.032 2.8929 7.1762
-44.748 -4.3851 -13.645 -9.6702
-4.5297 3.2928 0.11132 2.5998
相反,如果你有:
mD(j, i) = (mX(i, :) - mY(j, :)) * inv(mC) * (mX(i, :) - mY(j, :)).';
解决方案将转换为下一个列出的版本。
方法#1
A = reshape(bsxfun(@minus,permute(mY,[1 3 2]),permute(mX,[3 1 2])),[],p);
out = reshape(diag(A*inv(mC)*A.'),m,n);
方法#2
A = reshape(bsxfun(@minus,permute(mY,[1 3 2]),permute(mX,[3 1 2])),[],p);
imC = inv(mC);
out1 = zeros(m*n,1);
for i = 1:n*m
out(i) = A(i,:)*imC*A(i,:).'; %//'
end
out = reshape(out,m,n);
示例运行 -
>> n = 3; m = 4; p = 5;
mX = rand(n,p); mY = rand(m,p); mC = rand(p,p); imC = inv(mC);
>> %// Original solution
for i = 1:n
for j = 1:m
mD(j, i) = (mX(i, :) - mY(j, :)) * inv(mC) * (mX(i, :) - mY(j, :)).'; %//'
end
end
>> mD
mD =
0.81755 0.33205 0.82254
1.7086 1.3363 2.4209
0.36495 0.78394 -0.33097
0.17359 0.3889 -1.0624
>> %// Approach #1
A = reshape(bsxfun(@minus,permute(mY,[1 3 2]),permute(mX,[3 1 2])),[],p);
out = reshape(diag(A*inv(mC)*A.'),m,n); %//'
>> out
out =
0.81755 0.33205 0.82254
1.7086 1.3363 2.4209
0.36495 0.78394 -0.33097
0.17359 0.3889 -1.0624
>> %// Approach #2
A = reshape(bsxfun(@minus,permute(mY,[1 3 2]),permute(mX,[3 1 2])),[],p);
imC = inv(mC);
out1 = zeros(m*n,1);
for i = 1:n*m
out1(i) = A(i,:)*imC*A(i,:).'; %//'
end
out1 = reshape(out1,m,n);
>> out1
out1 =
0.81755 0.33205 0.82254
1.7086 1.3363 2.4209
0.36495 0.78394 -0.33097
0.17359 0.3889 -1.0624
答案 2 :(得分:1)
如果允许预处理矩阵mC
并且你不怕数字差异,似乎马哈拉诺比斯距离可以减少到普通的L2距离。
首先,计算mC
的Cholesky分解:
mR = chol(mC) % C = R^t * R, where R is upper-triangular
现在我们可以用这些因素来重新表述马哈拉诺比斯距离:
(Xi-Yj) * inv(C) * (Xi-Yj)^t = || (Xi-Yj) inv(R) ||^2 = ||TXi - TYj||^2
where: TXi = Xi * inv(R)
TYj = Yj * inv(R)
因此,我们的想法是首先将点Xi
,Yj
转换为TXi
,TYj
,然后计算它们之间的欧氏距离。这是算法大纲:
mR
- 协方差矩阵mC
的Cholesky因子( O(p ^ 3)时间。)mR
( O(p ^ 3)时间。mX
和mY
乘以右侧的inv(mR)
(取 O(p ^ 2(m + n))时间。总时间 O(m n p +(m + n)p ^ 2 + p ^ 3)与原始 O(m n p ^ 2)。当 1&lt;&lt; p <&lt; N,M 。在这种情况下,步骤4将花费大部分时间并且应该进行矢量化。
我对MATLAB没什么经验,但在x86 CPU上有很多SIMD矢量化。在原始计算中,沿着一个足够大的数组维度进行向量化就足够了,并为其他维度制作简单的循环。
如果您希望p
足够大,可能可以沿着点的坐标进行矢量化,并为i <= n
和j <= m
创建两个嵌套循环。这与@Daniel发布的相似。
如果p
不够大,您可以改为沿着其中一个点序列进行矢量化。这与@dpmcmlxxvi发布的解决方案类似:您必须从第二个矩阵的所有行中减去一行矩阵的单行,然后计算结果行的平方范数。重复n
次(
或m
次)。
至于我,完全矢量化(这意味着用矩阵运算而不是MATLAB中的循环重写)听起来并不像一个聪明的性能目标。最有可能部分矢量化解决方案的速度最快。
答案 3 :(得分:0)
我得出结论,矢量化这个问题效率不高。我对矢量化这个问题的最好想法是需要m x n x p x p工作内存,至少如果一次处理所有内容。这意味着当n = m = p = 152时,代码已经需要4GB Ram。在这些维度上,我的系统可以在不到一秒的时间内运行循环:
mD=zeros(size(mX,1),size(mY,1));
ImC=inv(mC);
for i=1:size(mX,1)
for j=1:size(mY,1)
d=mX(i, :) - mY(j, :);
mD(i, j) = (d) * ImC * (d).';
end
end