小编典典

如何使用 python + NumPy / SciPy 计算滚动/移动平均值?

all

似乎没有函数可以简单地计算 numpy/scipy上的移动平均值,从而导致复杂的解决方案。

我的问题有两个:

  • (正确)使用 numpy 实现移动平均线的最简单方法是什么?
  • 既然这看起来不简单且容易出错,那么是否有充分的理由不将电池包含在这种情况下?

阅读 69

收藏
2022-07-09

共1个答案

小编典典

实现此目的的一种简单方法是使用np.convolve.
这背后的想法是利用计算离散卷积的方式并使用它来返回
滚动平均值
。这可以通过与np.ones长度等于我们想要的滑动窗口长度的序列进行卷积来完成。

为此,我们可以定义以下函数:

def moving_average(x, w):
    return np.convolve(x, np.ones(w), 'valid') / w

该函数将采用序列的卷积x和长度为的序列w。请注意,选择mode的是valid卷积乘积仅针对序列完全重叠的点给出。


一些例子:

x = np.array([5,3,8,10,2,1,5,1,0,2])

对于具有长度窗口的移动平均线,2我们将有:

moving_average(x, 2)
# array([4. , 5.5, 9. , 6. , 1.5, 3. , 3. , 0.5, 1. ])

对于一个长度的窗口4

moving_average(x, 4)
# array([6.5 , 5.75, 5.25, 4.5 , 2.25, 1.75, 2.  ])

如何convolve工作?

让我们更深入地了解计算离散卷积的方式。以下函数旨在复制np.convolve计算输出值的方式:

def mov_avg(x, w):
    for m in range(len(x)-(w-1)):
        yield sum(np.ones(w) * x[m:m+w]) / w

对于上面的相同示例,这也会产生:

list(mov_avg(x, 2))
# [4.0, 5.5, 9.0, 6.0, 1.5, 3.0, 3.0, 0.5, 1.0]

因此,每一步所做的就是在数组和当前 窗口 之间取内积。在这种情况下,np.ones(w)考虑到我们直接取sum序列的 ,乘法是多余的。

Bellow 是如何计算第一个输出的示例,以便更清晰一些。假设我们想要一个窗口w=4

[1,1,1,1]
[5,3,8,10,2,1,5,1,0,2]
= (1*5 + 1*3 + 1*8 + 1*10) / w = 6.5

以下输出将计算为:

  [1,1,1,1]
[5,3,8,10,2,1,5,1,0,2]
= (1*3 + 1*8 + 1*10 + 1*2) / w = 5.75

依此类推,一旦执行了所有重叠,就返回序列的移动平均值。

2022-07-09