【问题标题】:How can I go through the columns of a matrix in matlab and add them each to a specific column of a sum matrix in matlab?如何在matlab中遍历矩阵的列并将它们分别添加到matlab中求和矩阵的特定列?
【发布时间】:2015-04-09 17:41:14
【问题描述】:

假设有一个矩阵

A =

 1     3     2    4
 4     2     5    8
 6     1     4    9

例如,我有一个包含此矩阵每一列的“类”的向量

v = [1 , 1 , 2 , 3]

如何将矩阵的列与一个新矩阵相加,作为列向量,每个列到其类的列?在此示例中,A 的第 1 列和第 2 列将添加到新矩阵的第一列,第 2 列添加到第 3 列到第 2 列,第 4 列添加到第 3 列。

喜欢

SUM =

4    2    4
6    5    8
7    4    9

没有循环可以吗?

【问题讨论】:

  • 不要害怕 MATLAB 循环!现在速度很快,而且通常很容易阅读!
  • @knedlsepp ...但消除了大部分乐趣:-P
  • @LuisMendo:嗯,我和下一个人一样喜欢一个好的矢量化解决方案,但是如果for-loop 胜过所有其他方法,为什么要避免呢? ;-)
  • 所以@user3563898 下面的任何答案对您有帮助吗?请将其中一项标记为已接受。谢谢!

标签: matlab matrix vector sum vectorization


【解决方案1】:

结合accumarraybsxfun 功能的完美场景之一-

%// Since we are to accumulate columns, first step would be to transpose A
At = A.'  %//'

%// Create a vector of linear IDs for use with ACCUMARRAY later on
idx = bsxfun(@plus,v(:),[0:size(A,1)-1]*max(v))

%// Use ACCUMARRAY to accumulate rows from At, i.e. columns from A based on the IDs
out = reshape(accumarray(idx(:),At(:)),[],size(A,1)).'

示例运行 -

A =
     1     3     2     4     6     0
     4     2     5     8     9     2
     6     1     4     9     8     9
v =
     1     1     2     3     3     2
out =
     4     2    10
     6     7    17
     7    13    17

【讨论】:

  • 不错。我试图弄清楚如何使用accumarray。 +1。
  • @Benoit_11 没有bsxfun,没有完美的解决方案! ;)
  • bsxfun, accumarraynon-conjugate 转置:令人愉快的答案! :-)
【解决方案2】:

accumarray 在 2D 中的替代方案。生成带有矢量v 的网格,然后应用accumarray

A = A.';

v = [1 1 2 3]; 

[X, Y] = ndgrid(v,1:size(A,2));

这里的XY 看起来像这样:

X =

     1     1     1
     1     1     1
     2     2     2
     3     3     3


Y =

     1     2     3
     1     2     3
     1     2     3
     1     2     3

然后申请accumarray:

B=accumarray([X(:) Y(:)],A(:)),

SUM = B.'

SUM =

     4     2     4
     6     5     8
     7     4     9

如您所见,使用[X(:) Y(:)] 创建以下数组:

ans =

     1     1
     1     1
     2     1
     3     1
     1     2
     1     2
     2     2
     3     2
     1     3
     1     3
     2     3
     3     3

其中包含“类”的向量v 被复制了 3 次,因为有 3 个唯一的类要加在一起。

编辑:

正如 knedlsepp 所指出的,您可以像这样摆脱对AB 的转置:

[X2, Y2] = ndgrid(1:size(A,1),v);

B = accumarray([X2(:) Y2(:)],A(:))

最终会做同样的事情。我发现使用转置更容易可视化,但结果相同。

【讨论】:

  • 不错。这对我来说更有意义。
  • 为什么要转置?你不能用:[X, Y] = ndgrid(1:size(A,1),v);吗?
  • 确实如此;我发现使用A 转置更容易可视化,但@knedlsepp 绝对正确。
  • 我多么希望 Mathworks 扩展 accumarray 以使用矩阵作为第二个参数...
  • @LuisMendo - 我也希望如此。这将使我开发的许多算法更容易编码。
【解决方案3】:

单线怎么样?

result = full(sparse(repmat(v,size(A,1),1), repmat((1:size(A,1)).',1,size(A,2)), A));

【讨论】:

  • full(sparse(... 而不是accumarray?我认为您不想发布与 Benoit_11 过于相似的解决方案。 ;-)
  • @knedlsepp Benoit_11 已经涵盖了accumarray 的方式:-) 并且使用sparse 的优点是可以直接使用columns 来完成累加,而不仅仅是使用数字正如accumarray 强迫你那样做。但仔细想想,是的,实际上非常相似
  • @knedlsepp 也许我应该删除它?
  • 这当然不是我的本意!
  • 我只是觉得力量受到干扰,#1 SO accumarrayrista 会选择 full(sparse。好吧,当 R2015a 最终安装在大多数机器上时,您可以使用accumarray 而不是丑陋的reshape(,[],1) 来使用repelem 而不是repmat 的单线。 :-)
【解决方案4】:

不要过早优化!

for 循环可以很好地解决您的问题:

out = zeros(size(A,1), max(v));
for i = 1:numel(v)
    out(:,v(i)) = out(:,v(i)) + A(:,i);
end

顺便说一句:很好,我的意思是:快,快,快!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-24
    • 1970-01-01
    • 1970-01-01
    • 2017-04-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多