Matlab:如果index在一个范围内,则求和相应的值

时间:2015-04-01 14:18:14

标签: arrays matlab vectorization

我一直在努力想办法加快速度。现在我的当前代码会在大约77,000个事件上循环约200秒。我希望有人可以帮助我加快速度,因为我必须做大约500个。

问题: 我有阵列(两者都是200000x1),对应于超过77000个事件的能量和位置。我将每个事件的范围分成两个数组,event_start和event_end。我做的第一件事是寻找特定范围内的位置,然后我将相应的能量放在它自己的数组中。为了从这些信息中得到我需要的东西,我遍历每个事件及其相应的开始/结束,以总结每个事件的所有能量。我的代码如下:

    indx_pos = find(pos>0.7 & pos<2.0);
    energy = HitEnergy(indx_pos);

    for i=1:n_events
        Etotal(i) = sum(energy(find(indx_pos>=event_start(i) …
        & indx_pos<=event_end(i))));    
    end

示例输入&amp;输出:

% Sample input 
% pos and energy same length

n_events = 3;
event_start = [1 3 7]';
event_end   = [2 6 8]';

pos = [0.75 0.8 2.1 3.6 1.9 0.5 21.0 3.1]';
HitEnergy = [0.002 0.004 0.01 0.0005 0.08  0.1 1.7 0.007]';


%  Sample Output
Etotal = 0.0060
         0.0800
              0

2 个答案:

答案 0 :(得分:2)

方法#1:通用案例

使用bsxfunmatrix-multiplication -

的一种方法
mask = bsxfun(@ge,indx_pos,event_start.') & bsxfun(@le,indx_pos,event_end.')
Etotal = energy.'*mask

如果memory-hungry中包含大量元素,则可能会indx_pos


方法#2:非重叠的开始/结束范围情况

对于这种特殊情况,可以使用accumarray,如此 -

%// Setup ID array for use in accumarray later on
loc(numel(pos))=0; %// Fast pre-allocation scheme
valids = event_end+1<=numel(pos);
loc(event_end(valids)+1) = -1*(1:sum(valids));
loc(event_start) = loc(event_start)+(1:numel(event_end));
id = cumsum(loc);

%// Set elements as zeros in HitEnergy that do not satisfy the criteria:
%// pos>0.7 & pos<2.0
HitEnergy_select = (pos>0.7 & pos<2.0).*HitEnergy(:);

%// Discard elments in HitEnergy_select & id that have IDs as zeros  
HitEnergy_select = HitEnergy_select(id~=0);
id = id(id~=0);

%// Accumulate summations as done inside the loop in the original code 
Etotal = accumarray(id(:),HitEnergy_select);

答案 1 :(得分:2)

问题是,对于您正在搜索整个向量indx_pos的每个事件。 将搜索范围内的搜索限制在event_start(i)event_end(i)的范围内:

for i = 1:n_events
    I = event_start(i):event_end(i);
    posIIsWithinRange = pos(I)>0.7 & pos(I)<2.0;
    Etotal(i) = sum(HitEnergy(I(posIIsWithinRange)));
end

您还可以使用基于run length decodingvectorizing the notion of colon的矢量化版本。 (下载函数coloncatrldrunLengthDecode。)

I = coloncatrld(event_start, event_end);
energy = HitEnergy(I);
eventNum = runLengthDecode(event_end - event_start+1);
posIIsWithinRange = pos(I)>0.7 & pos(I)<2.0;
Etotal = accumarray(eventNum(posIIsWithinRange), energy(posIIsWithinRange), [n_events,1]);

这类似于 Divakar 的方法#2,另外它也适用于重叠范围。