如何(有效)计算向量的移动平均值? [英] How can I (efficiently) compute a moving average of a vector?

查看:207
本文介绍了如何(有效)计算向量的移动平均值?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个向量,我想计算它的移动平均值(使用宽度为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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆