如何在没有for循环的情况下对矩阵的每一行执行操作?

时间:2014-09-18 14:21:54

标签: octave

我想在2个矩阵上对以下操作进行矢量化。

A是“k×m”矩阵,B是“n×m”矩阵。我定义了一个函数F(a,B),它对A的行“a”和整个矩阵B进行操作.F的输出是“1 x n”行向量。

我想将F(a,B)应用于A的每一行,并堆叠k“1 x n”结果行向量以形成最终的“k x n”矩阵。使用for循环时,此操作为:

result = [];
for i = 1:k
  result = [result ; F(A(i,:),B)];
endfor

有没有人知道如何在此操作中消除for循环?我可以使用类似“bsxfun”Octave内置函数的东西吗?

作为Octave的新人,如果我错过了一些明显的方法来执行此类操作,我很抱歉。

感谢您的任何建议。

编辑: 事实上,B可以被封装。我可以定义函数f(a),它在A的“1×m”行“a”上操作,使得f的输出是“1×n”行向量。然后,当使用for循环时,我的操作将变为:

result = zeros(k,n);
for i = 1:k
  result(i,:) = f(A(i,:));
endfor

我需要一次操作整行A(i,:),因为函数f需要A(i,:)中的整个信息来生成输出行向量。

因为m,n可能很大(几万或更多),我正在寻找方法来消除简单的for循环,试图让程序运行得更快。

我想知道Octave是否有一些内置函数用于矢量化我的这种情况。

4 个答案:

答案 0 :(得分:2)

使用ndparhttp://wiki.octave.org/NDpar_package, 你可以直接实现这个目标

pkg load ndpar

k = 3;
m = 2;

A = rand(k, m);
B = rand(m, k);

F = @(a, B)  a * B;

result_ndpar = ndpar_arrayfun(nproc, F, A, B, "IdxDimensions", [1, 0], "CatDimensions", [1])

"IdxDimensions"选项[1, 0]表示第一个参数A应沿第一个方向切片(并行化),第二个参数B不应切片(因此通过"按原样#34;)

"CatDimensions"选项[1]表示输出值应沿第一个方向连接。

答案 1 :(得分:1)

我认为F(a,B)类似于:

function F(a, B)
for i=1:size(B,1)
    result = f(a,B(i,:));
end

所以我将从这里开始,并在每个相应的行上应用f(a,b):

A = repmat (A, [n 1]); 
B = repmat (B, [k 1]); %(kxn) x m matrix

答案 2 :(得分:1)

首先,您应该检查for循环是否花费了相当多的时间,然后花费太多精力来删除它。您的主要问题是您在每次迭代时重新分配内存。 Matlab的编辑会警告你 - 我不确定Octave。对于小型阵列来说这不是什么大问题,但对于较大的阵列,重新分配很多次都会很昂贵。您只需要预先分配:

result = zeros(k,n);
for i = 1:k
    result(k,:) = F(A(i,:),B);
end

或者你可以改变索引的方向而不用打电话给zeros(小心这种技巧):

for i = k:-1:1
    result(k,:) = F(A(i,:),B);
end

要回答您的问题,bsxfun不能用于此类事情。它用于元素操作。如果您重新编写F函数(或者您可以通过矩阵数学运算完成所有操作),则可以使用它。如果你只是想摆脱循环以摆脱它,你可能会看arrayfun。但是,arrayfun只是伪装的for循环,并且通常比显式写循环慢。

答案 3 :(得分:1)

经过一些研究,我最终可以使用“mat2cell”,“cellfun”和“cell2mat”来对我的代码进行矢量化。 想法是将A的每一行转换为单元格C的单元格条目,然后将f(a)应用于C的每个单元格条目,最后将得到的单元格转换回矩阵。代码是:

C = mat2cell(A, ones(1,size(A,1)));
f = @(a) F(a,B);
result_cell = cellfun(f, C, "UniformOutput", false);
result = cell2mat(result_cell);

然而,这个矢量化代码的运行时间似乎与原始的“for循环”实现几乎相同。似乎一级“for循环”效率不是很低,或者只有当k很大时(即A有很多行)才会产生差异。此外,内置的“cellfun”可能不如其帮助状态那么有效:

  

`cellfun'函数是避免循环的有用工具。它通常与匿名函数句柄一起使用;但是,调用匿名函数涉及的开销与m文件函数的开销相当。将句柄传递给内置函数更快,因为解释器不参与内部循环。

希望我的答案也能为其他人提供一个很好的参考。