向AI轉型的程序員都關注了這個號👇👇👇html
人工智能大數據與深度學習 公衆號: datayxpython
本文的內容主要來源於博客:
https://www.analyticsvidhya.com/blog/2016/02/time-series-forecasting-codes-python/ 英文不錯的讀者能夠前去閱讀原文。git
在閱讀本文以前 ,推薦先閱讀:
時間序列預測之--ARIMA模型
http://www.cnblogs.com/bradleon/p/6827109.html
本文主要分爲四個部分:程序員
用pandas處理時序數據github
怎樣檢查時序數據的穩定性算法
怎樣讓時序數據具備穩定性微信
時序數據的預測機器學習
1. 用pandas導入和處理時序數據
第一步:導入經常使用的庫函數
import pandas as pd
import numpy as np
import matplotlib.pylab as plt
from matplotlib.pylab
import rcParams
#rcParams設定好畫布的大小
rcParams['figure.figsize'] = 15, 6
第二步:導入時序數據
數據文件可在github:post
關注微信公衆號 datayx 而後 回覆 「時序」 便可獲取。
data = pd.read_csv(path+"AirPassengers.csv")
print data.head()
print '\n Data types:'
print data.dtypes
運行結果以下:數據包括每月對應的passenger的數目。
能夠看到data已是一個DataFrame,包含兩列Month和#Passengers,其中Month的類型是object,而index是0,1,2...
第三步:處理時序數據
咱們須要將Month的類型變爲datetime,同時做爲index。
dateparse = lambda dates: pd.datetime.strptime(dates, '%Y-%m')
#---其中parse_dates 代表選擇數據中的哪一個column做爲date-time信息,
#---index_col 告訴pandas以哪一個column做爲 index
#--- date_parser 使用一個function(本文用lambda表達式代替),使一個string轉換爲一個datetime變量
data = pd.read_csv('AirPassengers.csv', parse_dates=['Month'], index_col='Month',date_parser=dateparse)
print data.head()
print data.index
結果以下:能夠看到data的index已經變成datetime類型的Month了。
2.怎樣檢查時序數據的穩定性(Stationarity)
由於ARIMA模型要求數據是穩定的,因此這一步相當重要。
1. 判斷數據是穩定的常基於對於時間是常量的幾個統計量:
常量的均值
常量的方差
與時間獨立的自協方差
用圖像說明以下:
均值
X是時序數據的值,t是時間。能夠看到左圖,數據的均值對於時間軸來講是常量,即數據的均值不是時間的函數,全部它是穩定的;右圖隨着時間的推移,數據的值總體趨勢是增長的,全部均值是時間的函數,數據具備趨勢,因此是非穩定的。方差
能夠看到左圖,數據的方差對於時間是常量,即數據的值域圍繞着均值上下波動的振幅是固定的,因此左圖數據是穩定的。而右圖,數據的振幅在不一樣時間點不一樣,因此方差對於時間不是獨立的,數據是非穩定的。可是左、右圖的均值是一致的。自協方差
一個時序數據的自協方差,就是它在不一樣兩個時刻i,j的值的協方差。能夠看到左圖的自協方差於時間無關;而右圖,隨着時間的不一樣,數據的波動頻率明顯不一樣,致使它i,j取值不一樣,就會獲得不一樣的協方差,所以是非穩定的。雖然右圖在均值和方差上都是與時間無關的,但還是非穩定數據。
2. python判斷時序數據穩定性
有兩種方法:
1.Rolling statistic-- 即每一個時間段內的平均的數據均值和標準差狀況。
Dickey-Fuller Test -- 這個比較複雜,大體意思就是在必定置信水平下,對於時序數據假設 Null hypothesis: 非穩定。
if 經過檢驗值(statistic)< 臨界值(critical value),則拒絕null hypothesis,即數據是穩定的;反之則是非穩定的。
from statsmodels.tsa.stattools import adfuller
def test_stationarity(timeseries):
#這裏以一年爲一個窗口,每個時間t的值由它前面12個月(包括本身)的均值代替,標準差同理。
rolmean = pd.rolling_mean(timeseries,window=12)
rolstd = pd.rolling_std(timeseries, window=12)
#plot rolling statistics:
fig = plt.figure()
fig.add_subplot()
orig = plt.plot(timeseries, color = 'blue',label='Original')
mean = plt.plot(rolmean , color = 'red',label = 'rolling mean')
std = plt.plot(rolstd, color = 'black', label= 'Rolling standard deviation')
plt.legend(loc = 'best')
plt.title('Rolling Mean & Standard Deviation')
plt.show(block=False)
#Dickey-Fuller test:
print 'Results of Dickey-Fuller Test:'
dftest = adfuller(timeseries,autolag = 'AIC') #dftest的輸出前一項依次爲檢測值,p值,滯後數,使用的觀測數,各個置信度下的臨界值
dfoutput = pd.Series(dftest[0:4],index = ['Test Statistic','p-value','#Lags Used','Number of Observations Used'])
for key,value in dftest[4].items():
dfoutput['Critical value (%s)' %key] = value
print dfoutput
ts = data['#Passengers']
test_stationarity(ts)
結果以下:
能夠看到,數據的rolling均值/標準差具備愈來愈大的趨勢,是不穩定的。
且DF-test能夠明確的指出,在任何置信度下,數據都不是穩定的。
3. 讓時序數據變成穩定的方法
讓數據變得不穩定的緣由主要有倆:
趨勢(trend)-數據隨着時間變化。好比說升高或者下降。
季節性(seasonality)-數據在特定的時間段內變更。好比說節假日,或者活動致使數據的異常。
因爲原數據值域範圍比較大,爲了縮小值域,同時保留其餘信息,經常使用的方法是對數化,取log。
ts_log = np.log(ts)
檢測和去除趨勢
一般有三種方法:
聚合 : 將時間軸縮短,以一段時間內星期/月/年的均值做爲數據值。使不一樣時間段內的值差距縮小。
平滑: 以一個滑動窗口內的均值代替原來的值,爲了使值之間的差距縮小
多項式過濾:用一個迴歸模型來擬合現有數據,使得數據更平滑。
本文主要使用平滑方法
Moving Average--移動平均
moving_avg = pd.rolling_mean(ts_log,12)
plt.plot(ts_log ,color = 'blue')
plt.plot(moving_avg, color='red')
能夠看出moving_average要比原值平滑許多。
而後做差:
ts_log_moving_avg_diff = ts_log-moving_avg
ts_log_moving_avg_diff.dropna(inplace = True)
test_stationarity(ts_log_moving_avg_diff)
能夠看到,作了處理以後的數據基本上沒有了隨時間變化的趨勢,DFtest的結果告訴咱們在95%的置信度下,數據是穩定的。
上面的方法是將全部的時間平等看待,而在許多狀況下,能夠認爲越近的時刻越重要。因此引入指數加權移動平均-- Exponentially-weighted moving average.(pandas中經過ewma()函數提供了此功能。)
# halflife的值決定了衰減因子alpha: alpha = 1 - exp(log(0.5) / halflife)expweighted_avg = pd.ewma(ts_log,halflife=12)
ts_log_ewma_diff = ts_log - expweighted_avg
test_stationarity(ts_log_ewma_diff)
能夠看到相比普通的Moving Average,新的數據平均標準差更小了。並且DFtest能夠獲得結論:數據在99%的置信度上是穩定的。
檢測和去除季節性
有兩種方法:1 差分化: 以特定滯後數目的時刻的值的做差
2 分解: 對趨勢和季節性分別建模在移除它們
Differencing--差分
ts_log_diff = ts_log - ts_log.shift()
ts_log_diff.dropna(inplace=True)
test_stationarity(ts_log_diff)
如圖,能夠看出相比MA方法,Differencing方法處理後的數據的均值和方差的在時間軸上的振幅明顯縮小了。DFtest的結論是在90%的置信度下,數據是穩定的。
3.Decomposing-分解
#分解(decomposing) 能夠用來把時序數據中的趨勢和週期性數據都分離出來:
from statsmodels.tsa.seasonal import seasonal_decompose
def decompose(timeseries):
# 返回包含三個部分 trend(趨勢部分) , seasonal(季節性部分) 和residual (殘留部分)
decomposition = seasonal_decompose(timeseries)
trend = decomposition.trend
seasonal = decomposition.seasonal
residual = decomposition.resid
plt.subplot(411)
plt.plot(ts_log, label='Original')
plt.legend(loc='best')
plt.subplot(412)
plt.plot(trend, label='Trend')
plt.legend(loc='best')
plt.subplot(413)
plt.plot(seasonal,label='Seasonality')
plt.legend(loc='best')
plt.subplot(414)
plt.plot(residual, label='Residuals')
plt.legend(loc='best')
plt.tight_layout()
return trend , seasonal, residual
如圖能夠明顯的看到,將original數據 拆分紅了三份。Trend數據具備明顯的趨勢性,Seasonality數據具備明顯的週期性,Residuals是剩餘的部分,能夠認爲是去除了趨勢和季節性數據以後,穩定的數據,是咱們所須要的。
#消除了trend 和seasonal以後,只對residual部分做爲想要的時序數據進行處理trend , seasonal, residual = decompose(ts_log)
residual.dropna(inplace=True)
test_stationarity(residual)
如圖所示,數據的均值和方差趨於常數,幾乎無波動(看上去比以前的陡峭,可是要注意他的值域只有[-0.05,0.05]之間),因此直觀上能夠認爲是穩定的數據。另外DFtest的結果顯示,Statistic值原小於1%時的Critical value,因此在99%的置信度下,數據是穩定的。
4. 對時序數據進行預測
假設通過處理,已經獲得了穩定時序數據。接下來,咱們使用ARIMA模型
對數據已經預測。ARIMA的介紹能夠見本目錄下的另外一篇文章。
step1: 經過ACF,PACF進行ARIMA(p,d,q)的p,q參數估計
由前文Differencing部分已知,一階差分後數據已經穩定,因此d=1。
因此用一階差分化的ts_log_diff = ts_log - ts_log.shift() 做爲輸入。
等價於
yt=Yt−Yt−1
做爲輸入。
先畫出ACF,PACF的圖像,代碼以下:
#ACF and PACF plots:from statsmodels.tsa.stattools import acf, pacf
lag_acf = acf(ts_log_diff, nlags=20)
lag_pacf = pacf(ts_log_diff, nlags=20, method='ols')#Plot ACF: plt.subplot(121)
plt.plot(lag_acf)
plt.axhline(y=0,linestyle='--',color='gray')
plt.axhline(y=-1.96/np.sqrt(len(ts_log_diff)),linestyle='--',color='gray')
plt.axhline(y=1.96/np.sqrt(len(ts_log_diff)),linestyle='--',color='gray')
plt.title('Autocorrelation Function')#Plot PACF:plt.subplot(122)
plt.plot(lag_pacf)
plt.axhline(y=0,linestyle='--',color='gray')
plt.axhline(y=-1.96/np.sqrt(len(ts_log_diff)),linestyle='--',color='gray')
plt.axhline(y=1.96/np.sqrt(len(ts_log_diff)),linestyle='--',color='gray')
plt.title('Partial Autocorrelation Function')
plt.tight_layout()
圖中,上下兩條灰線之間是置信區間,p的值就是ACF第一次穿過上置信區間時的橫軸值。q的值就是PACF第一次穿過上置信區間的橫軸值。因此從圖中能夠獲得p=2,q=2。
step2: 獲得參數估計值p,d,q以後,生成模型ARIMA(p,d,q)
爲了突出差異,用三種參數取值的三個模型做爲對比。
模型1:AR模型(ARIMA(2,1,0))
from statsmodels.tsa.arima_model import ARIMA
model = ARIMA(ts_log, order=(2, 1, 0))
results_AR = model.fit(disp=-1)
plt.plot(ts_log_diff)
plt.plot(results_AR.fittedvalues, color='red')
plt.title('RSS: %.4f'% sum((results_AR.fittedvalues-ts_log_diff)**2))
圖中,藍線是輸入值,紅線是模型的擬合值,RSS的累計平方偏差。
模型2:MA模型(ARIMA(0,1,2))
model = ARIMA(ts_log, order=(0, 1, 2))
results_MA = model.fit(disp=-1)
plt.plot(ts_log_diff)
plt.plot(results_MA.fittedvalues, color='red')
plt.title('RSS: %.4f'% sum((results_MA.fittedvalues-ts_log_diff)**2))
模型3:ARIMA模型(ARIMA(2,1,2))
model = ARIMA(ts_log, order=(2, 1, 2))
results_ARIMA = model.fit(disp=-1)
plt.plot(ts_log_diff)
plt.plot(results_ARIMA.fittedvalues, color='red')
plt.title('RSS: %.4f'% sum((results_ARIMA.fittedvalues-ts_log_diff)**2))
由RSS,可知模型3--ARIMA(2,1,2)的擬合度最好,因此咱們肯定了最終的預測模型。
step3: 將模型代入原數據進行預測
由於上面的模型的擬合值是對原數據進行穩定化以後的輸入數據的擬合,因此須要對擬合值進行相應處理的逆操做,使得它回到與原數據一致的尺度。
#ARIMA擬合的實際上是一階差分ts_log_diff,predictions_ARIMA_diff[i]是第i個月與i-1個月的ts_log的差值。#因爲差分化有一階滯後,因此第一個月的數據是空的,
predictions_ARIMA_diff = pd.Series(results_ARIMA.fittedvalues, copy=True)print predictions_ARIMA_diff.head()
#累加現有的diff,獲得每一個值與第一個月的差分(同log底的狀況下)。
#即predictions_ARIMA_diff_cumsum[i] 是第i個月與第1個月的ts_log的差值。
predictions_ARIMA_diff_cumsum = predictions_ARIMA_diff.cumsum()
#先ts_log_diff => ts_log=>ts_log => ts
#先以ts_log的第一個值做爲基數,複製給全部值,而後每一個時刻的值累加與第一個月對應的差值(這樣就解決了,第一個月diff數據爲空的問題了)
#而後獲得了predictions_ARIMA_log => predictions_ARIMA
predictions_ARIMA_log = pd.Series(ts_log.ix[0], index=ts_log.index)
predictions_ARIMA_log = predictions_ARIMA_log.add(predictions_ARIMA_diff_cumsum,fill_value=0)
predictions_ARIMA = np.exp(predictions_ARIMA_log)
plt.figure()
plt.plot(ts)
plt.plot(predictions_ARIMA)
plt.title('RMSE: %.4f'% np.sqrt(sum((predictions_ARIMA-ts)**2)/len(ts)))
5.總結
前面一篇文章,總結了ARIMA建模的步驟。
(1). 獲取被觀測系統時間序列數據;
(2). 對數據繪圖,觀測是否爲平穩時間序列;對於非平穩時間序列要先進行d階差分運算,化爲平穩時間序列;
(3). 通過第二步處理,已經獲得平穩時間序列。要對平穩時間序列分別求得其自相關係數ACF 和偏自相關係數PACF,經過對自相關圖和偏自相關圖的分析,獲得最佳的階層 p 和階數 q
(4). 由以上獲得的d、q、p,獲得ARIMA模型。而後開始對獲得的模型進行模型檢驗。
具體例子會在另外一篇文章中給出。
本文結合一個例子,說明python如何解決:
1.判斷一個時序數據是不是穩定。對應步驟(1)
怎樣讓時序數據穩定化。對應步驟(2)
使用ARIMA模型進行時序數據預測。對應步驟(3,4)
另外對data science感興趣的同窗能夠關注這個網站,乾貨還挺多的。
https://www.analyticsvidhya.com/blog/
搜索公衆號添加: datayx
深度學習、機器學習、數據分析、python
長按圖片,識別二維碼,點關注
本文分享自微信公衆號 - 機器學習AI算法工程(datayx)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。