有没有简单的方法来总结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
循环解决这个问题,或者是否有内置函数?
答案 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个元素。
数据:
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