向量化foor循环,其变量在每次迭代中都会增加

时间:2020-08-08 14:15:23

标签: matlab loops for-loop optimization octave

我试图通过摆脱一些for循环来优化代码的运行时间。但是,我有一个变量,该变量在每次迭代中都会增加,有时会重复索引。我在这里提供一个最小的示例:

a = [1 4 2 2 1 3 4 2 3 1]
b = [0.5 0.2 0.3 0.4 0.1 0.05 0.7 0.3 0.55 0.8]
c = [3 5 7 9]

for i = 1:10
    c(a(i)) = c(a(i)) + b(i)
end

理想情况下,我想通过以下方式进行计算:

c(a) = c(a) + b 

,但是显然它不会给我相同的结果,因为我不得不多次重新计算同一索引的值,所以这种将其向量化的方法将行不通。 另外,如果这很重要,我会在Matlab或Octave中工作。

非常感谢您的帮助,我不确定是否可以进行矢量化。


编辑:非常感谢您到目前为止的回答。我发现了accumarray,这是我以前不知道的,并且也理解为什么更改Matlab和Octave之间的for循环会给我这么不同的时间。我也更了解我的问题。我给出了一个太简单的示例,以为可以扩展,但是如果b是矩阵呢?

(此刻让我们忘记c):

a = [1 4 2 2 1 3 4 2 3 1]
b =[0.69  -0.41  -0.13  -0.13  -0.42  -0.14  -0.23  -0.17   0.22  -0.24;
   0.34  -0.39  -0.36   0.68  -0.66  -0.19  -0.58   0.78  -0.23   0.25;
  -0.68  -0.54   0.76  -0.58   0.24  -0.23  -0.44   0.09   0.69  -0.41;
   0.11  -0.14   0.32   0.65   0.26   0.82   0.32   0.29  -0.21  -0.13;
  -0.94  -0.15  -0.41  -0.56   0.15   0.09   0.38   0.58   0.72   0.45;
   0.22  -0.59  -0.11  -0.17   0.52   0.13  -0.51   0.28   0.15   0.19;
   0.18  -0.15   0.38  -0.29  -0.87   0.14  -0.13   0.23  -0.92  -0.21;
   0.79  -0.35   0.45  -0.28  -0.13   0.95  -0.45   0.35  -0.25  -0.61;
  -0.42   0.76   0.15   0.99  -0.84  -0.03   0.27   0.09   0.57   0.64;
   0.59   0.82  -0.39   0.13  -0.15  -0.71  -0.84  -0.43   0.93  -0.74]

我现在了解到,我要做的是每个组的rowSum,考虑到我使用的是Octave,我不能使用“ splitapply”。我试图归纳您的答案,但是accumarray无法用于矩阵,而且我也无法归纳@ rahnema1解决方案。所需的输出将是:

[0.34   0.26  -0.93  -0.56  -0.42  -0.76  -0.69  -0.02   1.87  -0.53; 
 0.22  -1.03   1.53  -0.21   0.37   1.54  -0.57   0.73   0.23  -1.15;
-0.20   0.17   0.04   0.82  -0.32   0.10  -0.24   0.37   0.72   0.83;
 0.52  -0.54   0.02   0.39  -1.53  -0.05  -0.71   1.01  -1.15   0.04]

“等同于”

[sum(b([1 5 10],:))
 sum(b([3 4 8],:))
 sum(b([6 9],:))
 sum(b([2 7],:))]

非常感谢,如果您认为我应该将此问题包含在另一个问题中,而不是添加编辑,那么我会这样做。

2 个答案:

答案 0 :(得分:6)

原始问题

可以通过accumarray完成:

a = [1 4 2 2 1 3 4 2 3 1];
b = [0.5 0.2 0.3 0.4 0.1 0.05 0.7 0.3 0.55 0.8];
c = [3 5 7 9];
c(:) = c(:) + accumarray(a(:), b(:));

这将b定义的组中的a中的值相加,并将其添加到原始c中。

已编辑的问题

如果b是矩阵,则可以使用

full(sparse(repmat(a, 1, size(b,1)), repelem(1:size(b,2), size(b,1)), b))

accumarray([repmat(a, 1, size(b,1)).' repelem(1:size(b,2), size(b,1)).'], b(:))

答案 1 :(得分:4)

矩阵乘法和隐式展开,可以使用(八度):

nc = numel(c);
c += b * (1:nc == a.');

对于大尺寸输入,使用稀疏矩阵可能会提高存储效率:

nc = numel(c);
nb = numel(b);
c += b * sparse(1:nb, a, 1, nb, nc);

Edit:如果b是矩阵,则可以将此解决方案扩展为:

nc = numel(c);
na = numel(a);
out = sparse(a, 1:na, 1, nc, na) * b;