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

Octave 如何在没有for循环的情况下对矩阵的每一行执行操作?,octave,Octave,我想在2个矩阵上对以下操作进行矢量化 A是“kxm”矩阵,B是“nxm”矩阵。我定义了一个函数F(a,B),它对a的一行“a”和整个矩阵B进行运算。F的输出是一个“1xn”行向量 我想将F(a,B)应用于a的每一行,并将k“1xn”结果行向量叠加,形成最终的“kxn”矩阵。使用for循环时,此操作为: result = []; for i = 1:k result = [result ; F(A(i,:),B)]; endfor 有人知道如何在这个操作中消除for循环吗?我可以使用类似于“

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

A是“kxm”矩阵,B是“nxm”矩阵。我定义了一个函数F(a,B),它对a的一行“a”和整个矩阵B进行运算。F的输出是一个“1xn”行向量

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

result = [];
for i = 1:k
  result = [result ; F(A(i,:),B)];
endfor
有人知道如何在这个操作中消除for循环吗?我可以使用类似于“bsxfun”倍频程的内置函数吗

作为一名八度音阶的新人,我很抱歉我错过了一些明显的方法来执行这些操作

谢谢你的建议

编辑: 事实上,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循环的方法,以使程序运行得更快

我想知道倍频程是否有一些内置函数来矢量化这种情况。

我假设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

首先,您应该检查
for
循环是否花费了相当长的时间,然后再花费太多的精力删除它。您的主要问题是在每次迭代中重新分配内存。Matlab的编辑器将警告您这一点-我不确定倍频程。这对于小型阵列来说并不是什么大问题,但对于大型阵列来说,多次重新分配可能代价高昂。您只需预先分配:

result = zeros(k,n);
for i = 1:k
    result(k,:) = F(A(i,:),B);
end
或者,您可以反转索引的方向,而不必麻烦调用
(使用此技术时要小心):


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

经过一些研究,我终于可以使用“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-file函数的开销。将句柄传递给内置函数更快,因为解释器不参与内部循环


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

使用
ndpar
包, 你可以直接做到这一点

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
不应切片(因此按“原样”传递)


“CatDimensions”
选项
[1]
意味着输出值应沿第一个方向连接。

在“repmat”之后,A和B的大小相同。但是,对于我的操作,A中的第i行与B中的第i行不对应。此外,m,n可能很大,所以在这种情况下“repmat”可能没有效率。嗨,你能详细说明这个函数在做什么吗?在我的例子中,F(a,B)是将“a”的每个元素乘以B的每一列,然后在第二维度上进行求和。然而,我想要的是一种对任何函数F(a,B)进行向量化的通用方法。我想我已经达到了这个目标(见我的答案),但似乎我不能获得很大的速度增益。我问题中的一级for循环似乎效率不高。因此,F(a,B)=sum(a*B,2)?“arrayfun”似乎无法解决我的问题。然而,一个类似的内置函数“cellfun”解决了这个问题。谢谢。然后,要在多个内核上并行运行,您可以将
cellfun
替换为
parcellfun
result\u cell=parcellfun(nproc,f,C,“UniformOutput”,false)。这是parcellfun的起始页:好提示。非常感谢。我刚刚上传的
ndpar
软件包提供了一个更加紧凑的解决方案;更多信息在我的solution@huntj“平行”方案似乎不错。在我的例子中,A有几行,B有几百行,两者都有数万列,并且正在运行几百次迭代。与“cellfun”相比,使用“parcellfun”将运行时间减少到60%左右。“parcellfun”功能可以利用我的台式计算机的所有4个核心的近100%。我将尝试您建议的“ndpar”包来比较结果。“ndpar”包更灵活/强大。与“cellfun”相比,使用“ndpar_arrayfun”将运行时间减少到65%左右。它似乎比“parcellfun”稍慢一些。然而,该软件包似乎与“并行”软件包相冲突
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])