Moving sum with variable window

The moving sum can be calculated in MATLAB with movsum. However, that function requires that the window be a scalar. Is there a faster way to calculate a moving sum when the window length varies without using a loop?
As it stands, I am working with two equally sized vectors. The first contains values to sum and the second contains window lengths. A for-loop is used to manually extract the required values from the first vector for each ith value (window length) in the second vector. It gets the job done, but it would be great if it could be optimized, as it is being run millions of times.
The window sizes in the second vector span a large enough range (e.g., 50) that it is not faster to pre-calculate moving sums for each window size and simply index into the corresponding pre-calculated vectors while looping.
If this question can be answered, I would also apply it to other moving functions, such as movmax and movmin.
Edited addition in response to Steven Lord's comment:
Yes, that is what I am asking. (Though the vectors are on the order of 100,000 in length with windows up to 500 in size.) Typically, sums are not centered, though. So, it would include the current and previous elements.
The following example should help:
% behavior like movsum(x,[y(i)-1 0])
% - not possible as movsum requires y to be a constant
% declare variables
x = 1:20;
y = [1 2 3 4 2 5 3 7 2 4 5 4 7 6 3 9 5 5 3 6];
s = zeros(1,20); % initialize vector for sums
% hand-calculated values
% s = [1 1+2 1+2+3 1+2+3+4 4+5 2+3+4+5+6 5+6+7 2+3+4+5+6+7+8 ...
% 8+9 7+8+9+10 7+8+9+10+11 9+10+11+12 7+8+9+10+11+12+13 ...
% 9+10+11+12+13+14 13+14+15 8+9+10+11+12+13+14+15+16 ...
% 13+14+15+16+17 14+15+16+17+18 17+18+19 15+16+17+18+19+20]
% s = [1 3 6 10 9 20 18 35 17 34 45 42 70 69 42 108 75 80 54 105]
% current loop method (would like to speed up this calculation)
for i = 1:20
s(i) = sum(x((i-y(i)+1):i));
end
disp(s)
1 3 6 10 9 20 18 35 17 34 45 42 70 69 42 108 75 80 54 105
% pre-compiled method described above
w_max = max(y);
s_arr = NaN(w_max,20);
for i = 1:w_max
s_arr(i,:) = movsum(x,[i-1 0]);
end
s = zeros(1,20); % initialize vector for sums
for i = 1:20
s(i) = s_arr(y(i),i);
end
disp(s)
1 3 6 10 9 20 18 35 17 34 45 42 70 69 42 108 75 80 54 105

4 件のコメント

Steven Lord
Steven Lord 2022 年 1 月 21 日
To make sure we understand what you're asking, can you give a (small) concrete example of your two equally sized vectors and what you want the result to be on those two vectors? For instance, if x is your data to sum:
x = 1:6;
and y is your vector of window lengths:
y = [1 3 4 2 1 2];
Do you want to take the sum of a window of length 1 around the first element of x for the first element of the result, the sum of a window of length 3 around the second element of x for the second element of the result, a window of length 4 around the third element of x, etc.?
Image Analyst
Image Analyst 2022 年 1 月 21 日
Do you want the window size to change as it scans along the array to be filtered? Or are you just running movmeans a bunch of times with window widths defined by a vector and taking the i'th result, like
x = rand(1000, 1);
windowWidths = [3, 4, 7, 9, 30, 64]
numExperiments = 2000000;
for n = 1 : numExperiments
% For each experiment, try all the different possible window widths.
for k = 1 : length(windowWidths)
thisWidth = windowWidths(k);
% Filter at every location:
filtered_x = movmean(x, thisWidth);
% Subsample:
filtered_x = filtered_x(1 : thisWidth : end);
end
end
goc3
goc3 2022 年 1 月 21 日
Steven, I responded to your comment by updating my question with an added example.
Image Analyst, the window size changes as it scans. See the specific example that I added above.
apiwat nonut
apiwat nonut 2023 年 10 月 3 日
Hi, now I found the problam as same as you so, if you have any solution please tell me too.

サインインしてコメントする。

 採用された回答

Matt J
Matt J 2023 年 10 月 3 日

3 投票

x = 1:20;
y = [1 2 3 4 2 5 3 7 2 4 5 4 7 6 3 9 5 5 3 6];
n=numel(x);
c=[0,cumsum(x)];
s=c(2:end)-c((2:n+1)-y)
s = 1×20
1 3 6 10 9 20 18 35 17 34 45 42 70 69 42 108 75 80 54 105

1 件のコメント

goc3
goc3 2023 年 10 月 3 日
This is great! It is most definitely faster. Thanks, Matt.
For anyone that may use this answer, I was able to optimize it a bit further by adding one line that removes an indexing step:
x = 1:20;
y = [1 2 3 4 2 5 3 7 2 4 5 4 7 6 3 9 5 5 3 6];
n = numel(x);
cx = cumsum(x);
c = [0, cx];
s = cx - c((2:n+1) - y);

サインインしてコメントする。

その他の回答 (0 件)

カテゴリ

ヘルプ センター および File ExchangeExecution Speed についてさらに検索

製品

リリース

R2021b

質問済み:

2022 年 1 月 21 日

コメント済み:

2023 年 10 月 3 日

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by