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可能已經變得有點臃腫了。

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,它計算指數移動的加權平均值)。第二組未包含在第一組(移動窗口函數)中的事實可能是因為指數加權變換不依賴于固定長度的窗口

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
依此類推,一旦完成所有重疊,就返回序列的移動平均值。
添加回答
舉報