MATLAB中索引的累计总和 [英] Cumulative sum over index in MATLAB
问题描述
考虑以下矩阵,其中第一列是索引,第二列-是值,第三列-是在索引更改后重置的累积总和:
Consider the following matrix, where the first column is the index, the second - is values, the third - is the cumulative sum which resets once the index changes:
1 1 1 % 1
1 2 3 % 1+2
1 3 6 % 3+3
2 4 4 % 4
2 5 9 % 4+5
3 6 6 % 6
3 7 13 % 6+7
3 8 21 % 13+8
3 9 30 % 21+9
4 10 10 % 10
4 11 21 % 10+11
如何使第三列避免循环?
How can one get the third column avoiding loops?
我尝试以下操作:
A = [1 1;... % Input
1 2;...
1 3;...
2 4;...
2 5;...
3 6;...
3 7;...
3 8;...
3 9;...
4 10;...
4 11];
CS = cumsum(A(:,2)); % cumulative sum over the second column
I = [diff(data(:,1));0]; % indicate the row before the index (the first column)
% changes
offset=CS.*I; % extract the last value of cumulative sum for a given
% index
offset(end)=[]; offset=[0; offset] %roll offset 1 step forward
[A, CS, offset]
结果是:
ans =
1 1 1 0
1 2 3 0
1 3 6 0
2 4 10 6
2 5 15 0
3 6 21 15
3 7 28 0
3 8 36 0
3 9 45 0
4 10 55 45
4 11 66 0
如果有一种简单的方法可以将上面矩阵的第四列转换成
So the problem would have been solved, if there were a trivial way to transform the fourth column of the matrix above into
O =
0
0
0
6
6
15
15
15
15
45
45
由于CS-O提供了所需的输出.
Since CS-O gives the desired output.
任何建议,我将不胜感激.
I would appreciate any suggestions.
推荐答案
Use accumarray
with a custom function:
result = accumarray(A(:,1), A(:,2), [], @(x) {cumsum(x)});
result = vertcat(result{:});
无论索引变化步长是否为1(如您的示例),此操作均有效.
This works irrespective of index changes being by a step of 1 (as in your example) or not.
以下方法可避免细胞,因此速度更快.在他的答案中查看@Divakar的出色基准测试(并查看他的解决方案,这是最快的):
The following approach is faster as it avoids cells. See @Divakar's excellent benchmarking in his answer (and see his solution, which is the fastest):
-
如果索引更改始终对应于增加1(如您的示例):
If index changes always correspond to an increase by 1 (as in your example):
last = find(diff(A(:,1)))+1; %// index of last occurrence of each index value
result = A(:,2); %// this will be cumsum'd, after correcting for partial sums
correction = accumarray(A(:,1), A(:,2)); %// correction to be applied for cumsum
result(last) = result(last)-correction(1:end-1); %// apply correction
result = cumsum(result); %// compute result
如果索引值更改的幅度可能大于1(即可能存在跳过"的值):这需要进行一些小的修改,从而稍微减慢速度.
If the index value can change by more than 1 (i.e. there may be "skipped" values): this requires a small modification that slightly slows things down.
last = find(diff(A(:,1)))+1; %// index of last occurrence of each index value
result = A(:,2); %// this will be cumsum'd, after correcting for partial sums
correction = accumarray(A(:,1), A(:,2), [], @sum, NaN); %// correction
correction = correction(~isnan(correction)); %// remove unused values
result(last) = result(last)-correction(1:end-1); %// apply correction
result = cumsum(result);
这篇关于MATLAB中索引的累计总和的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!