4

我有一个主矩阵,比如说

A=magic(5);

也是一个向量

v=[1;3;5;2;2];

我想以这种方式将 A 的元素逐行相加:将第一行从 v(1)st 元素添加到末尾,将第二行从 v(2)rd 元素添加到末尾,第三行从 v (3) 到最后的元素,以此类推。

我知道我可以使用 for 循环来做到这一点。但我想知道是否有一种矢量化的方式来做到这一点。

编辑: 让我用一个例子来澄清我的问题:假设 A 和 v 如上所述。

A =

 17    24     1     8    15
 23     5     7    14    16
  4     6    13    20    22
 10    12    19    21     3
 11    18    25     2     9

v =

 1
 3
 5
 2
 2

现在我想要一种方法来获得以下结果:

answer =
 65  % 17+24+1+8+15
 37  % 7+14+16
 22  % 22
 55  % 12+19+21+3
 54  % 18+25+2+9
4

2 回答 2

4

您可以cumsum沿行使用。解决方案有点复杂,所以我将从一个更简单的示例开始:

假设您想对i第 - 行的所有元素求和,A直到(包括)v(i)第 - 位: res_i = \sum_{k=1..v(i)} A_ik

m = size(A,1); % num of rows
csA = cumsum(A, 2); % cumsum along rows
res = csA( sub2ind( size(A), 1:m, v ) ); % pick the vi-th column for the i-th row

现在,对于你的问题,既然你想要从头到尾 的所有元素的总和v(i),我们需要相应地翻转A和改变v

[m n] = size(A);
fA = fliplr(A);
fv = n + 1 - v; % flip the meaning of v
csA = cumsum( fA, 2 ); 
res = csA( sub2ind( [m n], 1:m, fv ) ); % should do the trick...
于 2013-04-25T13:18:02.390 回答
3

我知道这有点作弊,但怎么样:

S = arrayfun(@(ii) sum(A(ii, v(ii):end)), 1:size(A,1)).';

通常我在使用时有点疲倦arrayfun,但在比较时:

% sample data
N = 5000;

A = magic(N);
v = randi(N, N,1);


% simple loop
tic
    S = zeros(N,1);
    for ii = 1:N
        S(ii) = sum(A(ii, v(ii):end));
    end
toc


% arrayfun solution    
tic
    S = arrayfun(@(ii) sum(A(ii, v(ii):end)), 1:N).';
toc

% Shai's solution 
tic
    [m n] = size(A);
    fA = fliplr(A);
    fv = n + 1 - v; 
    csA = cumsum( fA, 2 ); 
    res = csA( sub2ind( [m n], 1:m, fv.' ) ).';
toc

结果:

Elapsed time is 0.386280 seconds. % simple loop
Elapsed time is 0.473916 seconds. % arrayfun
Elapsed time is 0.495794 seconds. % Shai's solution

所以,arrayfun毕竟还不错。

但是这里有一个重要的点:从远处看一下实现。循环解决方案有多容易阅读/理解?矢量化解决方案怎么样?

考虑到这一点,还要看看表演。那是一个 5000x5000 矩阵......那里有 2500个元素......

现在,你真的想避免那个循环吗?

于 2013-04-25T13:44:53.427 回答