为了账号安全,请及时绑定邮箱和手机立即绑定

如何使用NumPy计算移动平均线?

如何使用NumPy计算移动平均线?

开满天机 2019-09-02 11:14:48
似乎没有简单计算numpy / scipy上的移动平均值的函数,导致复杂的解决方案。我的问题是双重的:用numpy(正确)实现移动平均线的最简单方法是什么?由于这看起来非常重要且容易出错,因此有充分的理由不在这种情况下包含电池吗?
查看完整描述

3 回答

?
翻阅古今

TA贡献1780条经验 获得超5个赞

如果你只是想要一个简单的非加权移动平均线,您可以轻松地实现它np.cumsum,这可能 是比基于FFT方法快:


编辑纠正了代码中Bean发现的一个错误的索引。编辑


def moving_average(a, n=3) :

    ret = np.cumsum(a, dtype=float)

    ret[n:] = ret[n:] - ret[:-n]

    return ret[n - 1:] / n


>>> a = np.arange(20)

>>> moving_average(a)

array([  1.,   2.,   3.,   4.,   5.,   6.,   7.,   8.,   9.,  10.,  11.,

        12.,  13.,  14.,  15.,  16.,  17.,  18.])

>>> moving_average(a, n=4)

array([  1.5,   2.5,   3.5,   4.5,   5.5,   6.5,   7.5,   8.5,   9.5,

        10.5,  11.5,  12.5,  13.5,  14.5,  15.5,  16.5,  17.5])

所以我猜答案是:它实现起来非常简单,而且numpy可能已经变得有点臃肿了。


查看完整回答
反对 回复 2019-09-02
?
撒科打诨

TA贡献1934条经验 获得超2个赞

NumPy缺乏特定的特定于域的功能可能是由于Core Team的纪律和对NumPy主要指令的保真度:提供N维数组类型,以及创建和索引这些数组的函数。像许多基本目标一样,这个目标并不小,NumPy非常出色。


(更大)的SciPy包含更大的域特定库集合(SciPy开发人员称为子包) - 例如,数值优化(优化),信号处理(信号)和积分微积分(积分)。


我的猜测是你所追求的功能至少在一个SciPy子包中(或许是scipy.signal); 然而,我会先看看SciPy scikits的集合,找出相关的scikit(s)并寻找那里感兴趣的功能。


Scikits是基于NumPy / SciPy独立开发的软件包,并针对特定的技术学科(例如,scikits-image,scikits-learn等)。其中一些(特别是用于数值优化的令人敬畏的OpenOpt)受到高度重视,成熟的项目早在选择居住在相对较新的scikits标题之前。该Scikits主页喜欢约30个这样的上述清单scikits,但至少数那些正在积极发展不再。


遵循这个建议会引导你到scikits-timeseries ; 但是,这个包裹不再处于积极发展之中; 实际上,Pandas已成为AFAIK,事实上 基于NumPy的时间序列库。


熊猫有几个可用于计算移动平均值的函数; 其中最简单的可能就是rolling_mean,你可以这样使用:


>>> # the recommended syntax to import pandas

>>> import pandas as PD

>>> import numpy as NP


>>> # prepare some fake data:

>>> # the date-time indices:

>>> t = PD.date_range('1/1/2010', '12/31/2012', freq='D')


>>> # the data:

>>> x = NP.arange(0, t.shape[0])


>>> # combine the data & index into a Pandas 'Series' object

>>> D = PD.Series(x, t)

现在,只需调用函数rolling_mean传递Series对象和窗口大小,在下面的示例中为10天。


>>> d_mva = PD.rolling_mean(D, 10)


>>> # d_mva is the same size as the original Series

>>> d_mva.shape

    (1096,)


>>> # though obviously the first w values are NaN where w is the window size

>>> d_mva[:3]

    2010-01-01         NaN

    2010-01-02         NaN

    2010-01-03         NaN

验证它是否有效 - 例如,比较原始系列中的值10 - 15与使用滚动平均值平滑的新系列


>>> D[10:15]

     2010-01-11    2.041076

     2010-01-12    2.041076

     2010-01-13    2.720585

     2010-01-14    2.720585

     2010-01-15    3.656987

     Freq: D


>>> d_mva[10:20]

      2010-01-11    3.131125

      2010-01-12    3.035232

      2010-01-13    2.923144

      2010-01-14    2.811055

      2010-01-15    2.785824

      Freq: D

Rolling_mean函数以及大约十几个其他函数在Rubric 移动窗口函数下的Pandas文档中非正式地分组; Pandas中第二个相关的函数组称为指数加权函数(例如,ewma,它计算指数移动的加权平均值)。第二组未包含在第一组(移动窗口函数)中的事实可能是因为指数加权变换不依赖于固定长度的窗口


查看完整回答
反对 回复 2019-09-02
?
慕后森

TA贡献1802条经验 获得超5个赞

实现这一目标的一种简单方法是使用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.  ])

细节


让我们更深入地了解计算离散卷积的方式。以下函数旨在复制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]

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


贝娄是如何计算第一个输出以使其更清晰的一个例子。让我们想要一个窗口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

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


查看完整回答
反对 回复 2019-09-02
  • 3 回答
  • 0 关注
  • 2150 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信