conv 功能就在您的身边:
>> x = 1:8;
>> y = conv(x, ones(1,5), 'valid')
y =
15 20 25 30
基准测试
三个答案,三种不同的方法……这是一个使用timeit的快速基准测试(不同的输入大小,固定窗口宽度为5);如果您认为需要对其进行改进,请随时在其中(在 cmets 中)戳洞。
conv 成为最快的方法;它大约是coin's approach (using filter) 的两倍,大约是Luis Mendo's approach (using cumsum) 的四倍。
这是另一个基准测试(固定输入大小为1e4,不同的窗口宽度)。在这里,Luis Mendo's cumsum approach 显然是赢家,因为它的复杂性主要取决于输入的长度,并且对窗口的宽度不敏感。
结论
总而言之,你应该
- 如果您的窗口相对较小,请使用
conv 方法,
- 如果您的窗口相对较大,请使用
cumsum 方法。
代码(用于基准测试)
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