考虑2个向量A = [20000000 x 1]
和B = [20000000 x 1 ]
我需要找到对应于B的每个唯一元素的所有A的总和。
虽然这看起来很简单,但这在MATLAB中将永远存在。
目前,我正在使用
u = unique(B);
length_u = length(u);
C = zeros(length_u,1);
for i = 1:length_u
C(i,1) = sum(A(B==u(i)));
end
有没有让它跑得更快?我尝试使用并行计算工具箱拆分循环并运行2 parfor
个循环(因为我只有2个核心)。还需要几个小时。
答案 0 :(得分:6)
您必须先看this answer
如果必须,您可以使用histc
和accumarray
A = randi( 500, 1, 100000 );
B = randi( 500, 1, 100000 );
ub = unique( B );
[ignore idx] = histc( B, [ub-.5 ub(end)+.5] );
C = accumarray( idx', A' )';
在ideone上查看与幼稚for
- 循环实施的玩具比较。
我们使用histc
的第二个结果将B
(以及后来的A
)的元素映射到ub
元素定义的区间( B
)。
然后使用accumarray
将A
所有条目的所有条目与idx
定义的映射相加。
注意:我假设B
的独特元素至少相差0.5。
答案 1 :(得分:3)
如果B
仅包含整数,则可以使用sparse
添加具有相同索引的元素的事实在一行中轻松完成:
C = nonzeros(sparse(B,1,A));
答案 2 :(得分:3)
进一步简化 Shai :
建议的代码A = randi( 500, 1, 100000 );
B = randi( 500, 1, 100000 );
[~,~,idb] = unique( B );
C = accumarray( idb', A' )';
此处"idb"
在Shai建议的代码中提供与"idx"
相同的向量。
答案 3 :(得分:1)
我修改了总和。而不是必须检查每个元素而不是它适合大小写(B==u(i)
),我对数组进行了排序,并在元素发生变化时停止了。从该元素开始下一个总和。这样我只需要在A中循环每个元素,而不是length_u
次。这是我使用的代码:
A= rand(100000,1);
B= round(rand(100000,1)*25000);
u = unique(B);
length_u = length(u);
C = zeros(length_u,1);
E = zeros(length_u,1);
tic;
for k = 1:length_u
C(k,1) = sum(A(B==u(k)));
end
t_OP=toc;
tic
D= sortrows([A,B],2);
n=1;
for l=1:numel(u)
m=n;
while m<numel(B) && D(m+1,2)==u(l)
m=m+1;
end
E(l,1) = sum(D(n:m,1));
n=m+1;
end
t_trial=toc;
display(t_OP)
display(t_trial)
我也使用了你的代码。您的代码所用的时间为:t_OP=10.9398
,我的修改时间为t_trial=0.0962
。希望这会有所帮助。我通过构建sum(E-C)
0
来确保代码有效。
编辑:Speedtest
我将它与 @Shai 的解决方案进行了比较。这导致了
t_OP =
10.8147
t_trial =
0.0984
t_Shai =
0.0154
编辑:@moarningsun评论
而不是使用while
- 循环。如果在构建总和之前对数组进行排序,则可以使用unique的第二个输出。
tic
A = randi( 25000, 1, 100000 );
B = randi( 25000, 1, 100000 );
D= sortrows([A',B'],2);
[u, idx] = unique(D(:,2));
idx = [idx; numel(D(:,2))+1];
for l=1:numel(u)
E(l,1) = sum(D(idx(l):idx(l+1)-1,1));
end
t_trial=toc;