总结Matlab中的每第n行

时间:2014-05-21 07:10:05

标签: matlab for-loop matrix indexing vectorization

有没有简单的方法来总结Matlab中的每一行? 让我们说:

A =

 1     2     3
 4     5     6
 7     8     9
10    11    12
13    14    15
16    17    18

我希望每两行添加一次,如下所示:row1+row3+row5,然后是row2+row4+row6,所以我的输出是:

B =

21    24    27
30    33    36

我知道可以通过sum(A(1:2:end,:))执行此操作,但如果您有大型矩​​阵和多个第n行,这是没有用的,for循环是另一种选择,但我无法获得它到目前为止工作。您是否有任何建议/解决方案如何通过for循环解决这个问题,或者是否有内置函数?

6 个答案:

答案 0 :(得分:6)

那怎么样?

B = cell2mat(arrayfun(@(x) sum(A(x:n:end,:)),1:n,'uni',0)')

我首先考虑使用accumarray,但它需要一个向量作为输入。如果您按照this answer进行操作,仍然可以。

另一种准确的选择:

[a,b] = size(A);
idx = bsxfun(@plus, 1:b,repmat([0:b:b*n-1]',a/n,1)) 
B = reshape(accumarray(idx(:),A(:)),b,[]).'

答案 1 :(得分:4)

如果您想避免arrayfun一般情况n,可以使用一些重塑方法。一种这样的方法可能是这个 -

[M,N] = size(A); %// Get the size of A for later usage
rowd = reshape(1:M,n,M/n)'; %// Get new row indices based on every nth selection
A1 = A(rowd(:),:); %// Reshaped A that has all the nth rows packed up consecutively for easing summing up
A2 = reshape(A1,M/n,[]); %// Reshape into a matrix with the number of rows equal to number of rows in each nth grouping
out = reshape(sum(A2),[],N); %// Get the final output by summing across columns and reshaping into the N-column format as with A

答案 2 :(得分:4)

所有解决方案的基准

(基准代码Thanks to Amro

function [t,v] = nthSum()
    n = 3; 
    A = randi(100,10000*n,3);

    % functions to compare
    fcns = {
        @() sum1(A,n);
        @() sum2(A,n);
        @() sum3(A,n);
        @() sum4(A,n);
        @() sum5(A,n);
        @() sum6(A,n);
    };

    % timeit
    t = zeros(6,1);
    for ii = 1:100;
        t = t + cellfun(@timeit, fcns);
    end

    % check results
    v = cellfun(@feval, fcns, 'UniformOutput',false);
    assert(isequal(v{:}));
end

function B = sum1(A,n)   %thewaywewalk#1
    [a,b] = size(A);
    idx = bsxfun(@plus, 1:b,repmat([0:b:b*n-1]',a/n,1)); 
    B = reshape(accumarray(idx(:),A(:)),b,[]).';
end

function B = sum2(A,n)  %thewaywewalk#2
    B = cell2mat(arrayfun(@(x) sum(A(x:n:end,:)),1:n,'uni',0)');
end

function B = sum3(A,n) %Dennis Jaheruddin
    B=zeros(n,size(A,2));

    for k=1:n
        B(k,:)=sum(A(k:n:end,:),1);
    end
end

function B = sum4(A,n) %Luis Mendo
    B = squeeze(sum(reshape(permute(A, [1 3 2]), n,[] ,size(A,2)), 2));
end

function B = sum5(A,n) % Bentoy13
    [k,l] = size(A);
    B = sum(reshape([A',zeros(l,mod(-k,n))],l,n,ceil(k/n)),3)';
end

function B = sum6(A,n) % Divakar
    [M,N] = size(A); 
    rowd = reshape(1:M,n,M/n)'; 
    A1 = A(rowd(:),:);
    A2 = reshape(A1,M/n,[]); 
    B = reshape(sum(A2),[],N);
end

每次运行100次,30000x3矩阵A

的结果
0.1616s   %// thewaywewalk#1
0.0667s   %// thewaywewalk#2
0.0499s   %// Dennis Jaheruddin
0.0211s   %// Luis Mendo
0.0791s   %// Bentoy13
0.0784s   %// Divakar   

明确的赢家&失败者,其余的非常接近。 特别是丹尼斯最简单的解决方案(for loop)是一流的;)

有趣的是如何更改大行的所有内容

每次运行100次,3000x1000矩阵A

的结果
6.5646s   %// thewaywewalk#1
2.6314s   %// thewaywewalk#2
2.5939s   %// Dennis Jaheruddin
0.6412s   %// Luis Mendo
4.1996s   %// Bentoy13
1.9975s   %// Divakar

行数表现

结果平均为1000次运行,输入矩阵大小从10 * 25到1e6 * 25个元素。

enter image description here

数据:

N               10          20          50          100         200         500         1e+03       2e+03       5e+03       1e+04       2e+04       5e+04   1e+05   2e+05   5e+05   1e+06
thewaywewalk #1     0.000282    0.000401    0.000399    0.000341    0.000276    0.000306    0.000358    0.000538    0.00109     0.0015      0.00283     0.0111  0.021   0.0427  0.112   0.224
thewaywewalk #2     7.15e-05    0.000106    0.000129    0.000137    0.000149    0.000262    0.000433    0.000929    0.00313     0.00581     0.0122      0.0289  0.0567  0.121   0.327   0.635
Divakar             3.21e-05    4.36e-05    4.65e-05    4.63e-05    4.52e-05    6.86e-05    0.000116    0.00024     0.000668    0.00179     0.00378     0.00962 0.0193  0.0442  0.116   0.245
Bentoy13            4.58e-05    6.48e-05    7.43e-05    7.31e-05    7.16e-05    0.000103    0.000192    0.000387    0.00115     0.0028      0.00585     0.015   0.0303  0.0623  0.158   0.298
Dennis Jaheruddin   3.76e-05    5.54e-05    6.07e-05    6.25e-05    6.47e-05    0.000114    0.000183    0.000376    0.000999    0.00165     0.00345     0.0162  0.0318  0.0657  0.163   0.326
Luis Mendo          7.44e-05    0.000108    0.00011     9.45e-05    7.83e-05    8.56e-05    0.000102    0.000154    0.000323    0.000452    0.000892    0.00203 0.00374 0.00741 0.0186  0.0368

对于小矩阵(1000行以下),Divakar的解决方案速度最快;对于大型矩阵,Luis Mendo的解决方案显然是最好的。

答案 3 :(得分:3)

即使已经有一个已接受的答案,让我们尝试不同的方式。

这里的想法是将原始矩阵重塑为3D阵列,以便沿着一个维度进行总结。但我们必须注意A的大小可能不是n的倍数这一事实。

让我们从一些符号开始:

[k,l] = size(A);

为了重塑,我们必须有k=n*x(x整数)。如果不是这种情况,我们必须使用0行填充A.如果k=n*x+y,y是n的欧几里德除法的提示,我们必须将0行的0连接到A(或0是y == 0)。使用Matlab mod函数,它转换为:

A1 = [A;zeros(mod(-k,n),l)];

回想一下,mod(-k,n)是积极的。

现在,您想要对行而不是列进行求和:我们希望获得一个3D数组,其中行保持不变,列分布在行上。所以我必须转置数组,然后重塑它:

A2 = reshape(A1',l,n,ceil(k/n));

然后,您的结果只是第三维的总和,转回:

B = sum(A2,3)';

作为一个结论,让我们建立一个近乎单行的(为了清楚起见,我把k和l分开了......好吧,为了简洁):

[k,l] = size(A);
B = sum(reshape([A',zeros(l,mod(-k,n))],l,n,ceil(k/n)),3)';

答案 4 :(得分:3)

置换尺寸和重塑:

B = squeeze(sum(reshape(permute(A, [1 3 2]), n,[],size(A,2)), 2));

答案 5 :(得分:1)

我仍然认为for循环在这里很简单,如果你有很长的矩阵,可能效率很高:

A = [ 1     2     3
 4     5     6
 7     8     9
10    11    12
13    14    15
16    17    18];

n=2;
result=zeros(n,size(A,2));

for k=1:n
   result(k,:)=sum(A(k:n:end,:),1);
end