如何(有效)计算向量的移动平均值? [英] How can I (efficiently) compute a moving average of a vector?
问题描述
我有一个向量,我想计算它的移动平均值(使用宽度为5的窗口).
I've got a vector and I want to calculate the moving average of it (using a window of width 5).
例如,如果所讨论的向量是[1,2,3,4,5,6,7,8]
,则
For instance, if the vector in question is [1,2,3,4,5,6,7,8]
, then
- 结果向量的第一个条目应为
[1,2,3,4,5]
中所有条目的总和(即15
); - 结果向量的第二个条目应为
[2,3,4,5,6]
中所有条目的总和(即20
); - 等
- the first entry of the resulting vector should be the sum of all entries in
[1,2,3,4,5]
(i.e.15
); - the second entry of the resulting vector should be the sum of all entries in
[2,3,4,5,6]
(i.e.20
); - etc.
最后,所得向量应为[15,20,25,30]
.我该怎么办?
In the end, the resulting vector should be [15,20,25,30]
. How can I do that?
推荐答案
conv
功能就在您的小巷上:
The conv
function is right up your alley:
>> x = 1:8;
>> y = conv(x, ones(1,5), 'valid')
y =
15 20 25 30
基准
Benchmark
Three answers, three different methods... Here is a quick benchmark (different input sizes, fixed window width of 5) using timeit
; feel free to poke holes in it (in the comments) if you think it needs to be refined.
conv
成为最快的方法.它大约是硬币的方法(使用filter
)的两倍,并且是
conv
emerges as the fastest approach; it's about twice as fast as coin's approach (using filter
), and about four times as fast as Luis Mendo's approach (using cumsum
).
这是另一个基准(1e4
的固定输入大小,不同的窗口宽度).在这里,路易斯·门多(Luis Mendo)的cumsum
方法成为明显的赢家,因为它的复杂性主要取决于输入的长度.并且对窗口的宽度不敏感.
Here is another benchmark (fixed input size of 1e4
, different window widths). Here, Luis Mendo's cumsum
approach emerges as the clear winner, because its complexity is primarily governed by the length of the input and is insensitive to the width of the window.
总结一下,您应该
- 如果您的窗口相对较小,请使用
conv
方法 - 如果您的窗口相对较大,请使用
cumsum
方法.
- use the
conv
approach if your window is relatively small, - use the
cumsum
approach if your window is relatively large.
function benchmark
clear all
w = 5; % moving average window width
u = ones(1, w);
n = logspace(2,6,60); % vector of input sizes for benchmark
t1 = zeros(size(n)); % preallocation of time vectors before the loop
t2 = t1;
th = t1;
for k = 1 : numel(n)
x = rand(1, round(n(k))); % generate random row vector
% Luis Mendo's approach (cumsum)
f = @() luisMendo(w, x);
tf(k) = timeit(f);
% coin's approach (filter)
g = @() coin(w, u, x);
tg(k) = timeit(g);
% Jubobs's approach (conv)
h = @() jubobs(u, x);
th(k) = timeit(h);
end
figure
hold on
plot(n, tf, 'bo')
plot(n, tg, 'ro')
plot(n, th, 'mo')
hold off
xlabel('input size')
ylabel('time (s)')
legend('cumsum', 'filter', 'conv')
end
function y = luisMendo(w,x)
cs = cumsum(x);
y(1,numel(x)-w+1) = 0; %// hackish way to preallocate result
y(1) = cs(w);
y(2:end) = cs(w+1:end) - cs(1:end-w);
end
function y = coin(w,u,x)
y = filter(u, 1, x);
y = y(w:end);
end
function jubobs(u,x)
y = conv(x, u, 'valid');
end
function benchmark2
clear all
w = round(logspace(1,3,31)); % moving average window width
n = 1e4; % vector of input sizes for benchmark
t1 = zeros(size(n)); % preallocation of time vectors before the loop
t2 = t1;
th = t1;
for k = 1 : numel(w)
u = ones(1, w(k));
x = rand(1, n); % generate random row vector
% Luis Mendo's approach (cumsum)
f = @() luisMendo(w(k), x);
tf(k) = timeit(f);
% coin's approach (filter)
g = @() coin(w(k), u, x);
tg(k) = timeit(g);
% Jubobs's approach (conv)
h = @() jubobs(u, x);
th(k) = timeit(h);
end
figure
hold on
plot(w, tf, 'bo')
plot(w, tg, 'ro')
plot(w, th, 'mo')
hold off
xlabel('window size')
ylabel('time (s)')
legend('cumsum', 'filter', 'conv')
end
function y = luisMendo(w,x)
cs = cumsum(x);
y(1,numel(x)-w+1) = 0; %// hackish way to preallocate result
y(1) = cs(w);
y(2:end) = cs(w+1:end) - cs(1:end-w);
end
function y = coin(w,u,x)
y = filter(u, 1, x);
y = y(w:end);
end
function jubobs(u,x)
y = conv(x, u, 'valid');
end
这篇关于如何(有效)计算向量的移动平均值?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!