我有2个数组,A和B.我想形成一个与B相同尺寸的新数组C,其中每个元素将显示A(&)的SUM(A)。乙
以下是我的工作代码
A = [1:1:1000]
B=[1:1:100]
for n = 1:numel(B)
C(n) = sum(A(A>B(n)));
end
然而,当A有数百万行且B有数千行时,我必须对20个阵列对进行类似的计算,这需要花费大量时间。
有没有更快的方法?
例如,histcounts非常快,但它很重要,而不是求和。
由于
答案 0 :(得分:7)
根据数组的大小(以及内存限制),以下代码可能会稍快一些:
C = A*bsxfun(@gt,A',B);
然而,虽然它被矢量化,但似乎是内存分配的瓶颈(可能)。我想看看能否进一步加速。根据您的输入矢量大小,我发现大型矢量的速度提高了2倍。
答案 1 :(得分:6)
这是一种更快的方法,但我确信有更好的方法可以解决这个问题。
a=sort(A); %// If A and B are already sorted then this isn't necessary!
b=sort(B);
c(numel(B))=0; %// Initialise c
s=cumsum(a,2,'reverse'); %// Get the partial sums of a
for n=1:numel(B)
%// Pull out the sum for elements in a larger than b(n)
c(n)=s(find(a>b(n),1,'first'));
end
根据一些非常粗略的测试,这似乎比原始方法快两倍。
答案 2 :(得分:5)
你有histcounts
的正确想法,因为你基本上是"积累"基于A
的某些binning
元素。可以使用histc
完成此分箱操作。在这篇文章中列出的解决方案是从@David's answer
中列出的类似步骤开始,然后使用histc
来汇总和总结来自A
的选择性元素,以获得所需的输出和所有它以矢量化的方式。这是实施 -
%// Sort A and B and also get sorted B indices
sA = sort(A);
[sB,sortedB_idx] = sort(B);
[~,bin] = histc(sB,sA); %// Bin sorted B onto sorted A
C_out = zeros(1,numel(B)); %// Setup output array
%// Take care of the case when all elements in B are greater than A
if sA(1) > sB(end)
C_out(:) = sum(A);
end
%// Only do further processing if there is at least one element in B > any element in A
if any(bin)
csA = cumsum(sA,'reverse'); %// Reverse cumsum on sorted A
%// Get sum(A(A>B(n))) for every n, but for sorted versions
valid_mask = cummax(bin) - bin ==0;
valid_mask2 = bin(valid_mask)+1 <= numel(A);
valid_mask(1:numel(valid_mask2)) = valid_mask2;
C_out(valid_mask) = csA(bin(valid_mask)+1);
%// Rearrange C_out to get back in original unsorted version
[~,idx] = sort(sortedB_idx);
C_out = C_out(idx);
end
另外,请记住在比较此方法的结果与原始for循环版本的结果时,输出会有轻微变化,因为此向量化解决方案使用cumsum
计算运行总和,因此会有大的累积求和数加到相对非常小的单个元素,而for循环版本
只会选择元素。所以,floating-precision issues
会出现在那里。