获得所有矩阵的所有双因素产品'行列

时间:2016-10-27 09:57:20

标签: matlab performance vectorization

我有一个n x m矩阵。让该矩阵的某一行表示为x。每行代表一些功能x1, x2, x3, ...

现在,我希望收到x * x'对角线以上的元素,即:x1*x2, x1*x3, x2*x3,...但不是x1*x1。另外,如果我有x1*x2,则不需要x2*x1

我想将这些列与产品一起添加到我的矩阵中。鉴于我之前有m列,我会为这些产品添加其他列,即:(m^2 + m)/2 - m列。

这应该为我的矩阵的每一行完成。

我已经在Matlab中找到了解决方案。然而,它似乎非常缓慢,我想知道是否有更多的矢量化解决方案,Matlab可以更快地执行。

我当前的解决方案使用包来获取上对角线上方元素的向量:https://de.mathworks.com/matlabcentral/fileexchange/23391-triangular-and-diagonal-indexing

矩阵M(itriu(size(M),1))

M将在对角线上方提供矩阵元素。例如,如果我投入[1 2 3; 4 5 6; 7 8 9],我将得到2 3 6作为结果。

我的代码如下:

function [ X_out ] = permutateFeatures( X_in )
%PERMUTATEFEATURES given a matrix with m features in the columns
% and n samples in the rows, return a [n (m^2 + m)/2] matrix
% where each additional column contains a element-wise product of two of
% the original columns

n = size(X_in, 1);
m = size(X_in, 2);

X_out = [X_in zeros(n, (m^2 + m)/2 - m)];

for i = 1:n
    outerProduct = X_out(i,1:m)' * X_out(i,1:m);
    X_out(i,:) = [X_in(i,:) outerProduct(itriu(size(outerProduct),1))'];
end

end

是否有更有效的解决方案?

2 个答案:

答案 0 :(得分:2)

这是一个矢量化解决方案 -

[r,c] = find(triu(true(size(X_in,2)),1));
out = [X_in X_in(:,r).*X_in(:,c)];

运行时测试

时间码 -

% Setup input array 
% (as stated in comments : m is mostly <20. n goes into the millions)
X_in = randi(5,[50000,20]);

disp('--------------------------- Original Solution')
tic,
n = size(X_in, 1);
m = size(X_in, 2);
X_out = [X_in zeros(n, (m^2 + m)/2 - m)];
for i = 1:n
    outerProduct = X_out(i,1:m)' * X_out(i,1:m);
    X_out(i,:) = [X_in(i,:) outerProduct(itriu(size(outerProduct),1))'];
end
toc

disp('--------------------------- Proposed Solution')
tic,
[r,c] = find(triu(true(size(X_in,2)),1));
out = [X_in X_in(:,r).*X_in(:,c)];
toc,

计时 -

--------------------------- Original Solution
Elapsed time is 8.618389 seconds.
--------------------------- Proposed Solution
Elapsed time is 0.131146 seconds.

60x+ 的巨大加速!

答案 1 :(得分:1)

这里矩阵乘法是矢量化的,这是计算中更大的部分。如果你愿意,你也可以矢量化vec1和vec2的创建,但只有更多的效率:

vec1=[];
vec2=[];
for i = 1:n
    vec1=[vec1 i*ones(1,n-i)];
    vec2=[vec2 (i+1):n];
end
X_out2=[X_in X_in(:,vec1).*X_in(:,vec2)];

对于rand(1000,1000)旧方法而言,执行此方法

Elapsed time is 24.709988 seconds.
Elapsed time is 6.753230 seconds.

在我的机器上,使用相同的解决方案。