数组中的条件求和

时间:2015-07-19 23:16:40

标签: arrays performance matlab

我有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非常快,但它很重要,而不是求和。

由于

3 个答案:

答案 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会出现在那里。