时间序列预测:使用Python创建季节性ARIMA模型

栏目: Python · 发布时间: 5年前

内容简介:此文与先前的数据集:波特兰公共交通系统的每月乘客数量数据,链接: https://pan.baidu.com/s/1C2IATlb65VQ4FkWZX7RM8A 提取码: fm4v 。

此文与先前的 时间序列预测初学者指南(Python) 的内容类似,只不过中间多了一个季节性的的内容,在学习前,建议先学习 时间序列建模完整教程(R语言) 这篇文章。此文非原创,内容来自与翻译,原文链接见文末。

数据集:波特兰公共交通系统的每月乘客数量数据,链接: https://pan.baidu.com/s/1C2IATlb65VQ4FkWZX7RM8A 提取码: fm4v 。

加载数据,观察数据

%matplotlib inline
 
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import datetime
from dateutil.relativedelta import relativedelta
import seaborn as sns
import statsmodels.api as sm  
from statsmodels.tsa.stattools import acf  
from statsmodels.tsa.stattools import pacf
from statsmodels.tsa.seasonal import seasonal_decompose
 
df = pd.read_csv('portland-oregon-average-monthly.csv', parse_dates=['month'], index_col='month')
print(df.head())
df['riders'].plot(figsize=(12,8), title= 'Monthly Ridership', fontsize=14)
plt.savefig('month_ridership.png', bbox_inches='tight')

时间序列预测:使用 <a href='https://www.codercto.com/topics/20097.html'>Python</a> 创建季节性ARIMA模型

分解数据:

decomposition = seasonal_decompose(df['riders'], freq=12)
fig = plt.figure()  
fig = decomposition.plot()  
fig.set_size_inches(12, 6)

时间序列预测:使用Python创建季节性ARIMA模型

时间序列稳定化

测试方法:

from statsmodels.tsa.stattools import adfuller
def test_stationarity(timeseries):
    
    #Determing rolling statistics
    rolmean = timeseries.rolling(window=12).mean()
    rolstd = timeseries.rolling(window=12).std()
 
    #Plot rolling statistics:
    fig = plt.figure(figsize=(12, 8))
    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 Std')
    plt.legend(loc='best')
    plt.title('Rolling Mean & Standard Deviation')
    plt.show()
    
    #Perform Dickey-Fuller test:
    print('Results of Dickey-Fuller Test:')
    dftest = adfuller(timeseries, autolag='AIC')
    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)

测试序列稳定性:

test_stationarity(df['riders'])

时间序列预测:使用Python创建季节性ARIMA模型

看以看到整体的序列并没有到达稳定性要求,要 将时间序列转为平稳序列 ,有如下几种方法:

  • Deflation by CPI
  • Logarithmic(取对数)
  • First Difference(一阶差分)
  • Seasonal Difference(季节差分)
  • Seasonal Adjustment

这里会尝试取对数、一阶查分、季节差分三种方法,先进行一阶差分,去除增长趋势后检测稳定性:

df['first_difference'] = df['riders'].diff(1)  
test_stationarity(df['first_difference'].dropna(inplace=False))

时间序列预测:使用Python创建季节性ARIMA模型

可以看到图形上看上去变稳定了,但p-value的并没有小于0.05。再来看看12阶查分(即季节查分),看看是否稳定:

df['seasonal_difference'] = df['riders'].diff(12)  
test_stationarity(df['seasonal_difference'].dropna(inplace=False))

时间序列预测:使用Python创建季节性ARIMA模型

从图形上,比一阶差分更不稳定(虽然季节指标已经出来了),我们再来将一阶查分和季节查分合并起来,再来看下:

df['seasonal_first_difference'] = df['first_difference'].diff(12)  
test_stationarity(df['seasonal_first_difference'].dropna(inplace=False))

时间序列预测:使用Python创建季节性ARIMA模型

可以看到,在一阶差分后再加上季节差分,数据终于稳定下了。P-value小于了0.05,并且Test Statistic的值远远小于Critical Value (5%)的值。

在《Analysis of Financial Time Series》提到,对原始数据取对数有两个用处:第一个是将指数增长转为线性增长;第二可以平稳序列的方差。再来看看取对数的数据:

df['riders_log']= np.log(df['riders'])
test_stationarity(df['riders_log'])

时间序列预测:使用Python创建季节性ARIMA模型

取对数后,从图形上看有些稳定了,但p-value还是没有接近0.05,没能达稳定性要求。在此基础上我们再来做下一阶差分,去除增长趋势:

df['log_first_difference'] = df['riders_log'].diff(1)  
test_stationarity(df['log_first_difference'].dropna(inplace=False))

时间序列预测:使用Python创建季节性ARIMA模型

还是没能满足需求,我们再来对对数进行季节性差分:

df['log_seasonal_difference'] = df['riders_log'].diff(12)  
test_stationarity(df['log_seasonal_difference'].dropna(inplace=False))

时间序列预测:使用Python创建季节性ARIMA模型

还是没能满足需求,再来试试在对数基础上进行一阶差分+季节差分的效果:

df['log_seasonal_first_difference'] = df['log_first_difference'].diff(12)  
test_stationarity(df['log_seasonal_first_difference'].dropna(inplace=False))

时间序列预测:使用Python创建季节性ARIMA模型

可以看到稳定了满足需求了,但是稳定性相比不取对数的情况下,并没有提升而是下降了。

绘制ACF和PACF图,找出最佳参数

fig = plt.figure(figsize=(12,8))
ax1 = fig.add_subplot(211)
fig = sm.graphics.tsa.plot_acf(df['seasonal_first_difference'].iloc[13:], lags=40, ax=ax1) #从13开始是因为做季节性差分时window是12
ax2 = fig.add_subplot(212)
fig = sm.graphics.tsa.plot_pacf(df['seasonal_first_difference'].iloc[13:], lags=40, ax=ax2)

时间序列预测:使用Python创建季节性ARIMA模型

一直搞不清楚这2张图怎么看。今天一起来学习下:(貌似下面的内容也是糊里糊涂的,后续还需更深入的学习)

如何确定差分阶数和常数项:

  • 假如时间序列在很高的lag(10以上)上有正的ACF,则需要很高阶的差分
  • 假如lag-1的ACF是0或负数或者非常小,则不需要很高的差分,假如lag-1的ACF是-0.5或更小,序列可能overdifferenced。
  • 最优的差分阶数一般在最优阶数下标准差最小(但并不是总数如此)
  • 模型不查分意味着原先序列是平稳的;1阶差分意味着原先序列有个固定的平均趋势;二阶差分意味着原先序列有个随时间变化的趋势
  • 模型没有差分一般都有常数项;有两阶差分一般没常数项;假如1阶差分模型非零的平均趋势,则有常数项

如何确定AR和MA的阶数:

  • 假如PACF显示截尾或者lag-1的ACF是正的(此时序列仍然有点underdifferenced),则需要考虑AR项;PACF的截尾项表明AR的阶数
  • 假如ACF显示截尾或者lag-1的ACF是负的(此时序列有点overdifferenced),则需要加MA项,ACF的截尾项表明AR的阶数
  • AR和MA可以相互抵消对方的影响,所以假如用AR-MA模型去拟合数据,仍然需要考虑加些AR或MA项。尤其在原先模型需要超过10次的迭代去converge。
  • 假如在AR部分有个单位根(AR系数和大约为1),此时应该减少一项AR增加一次差分
  • 假如在MA部分有个单位根(MA系数和大约为1),此时应该减少一项AR减少一次差分
  • 假如长期预测出现不稳定,则可能AR、MA系数有单位根

如何确定季节性部分:

  • 假如序列有显著是季节性模式,则需要用季节性差分,但是不要使用两次季节性差分或总过超过两次差分(季节性和非季节性)
  • 假如差分序列在滞后s处有正的ACF,s是季节的长度,则需要加入SAR项;假如差分序列在滞后s处有负的ACF,则需要加入SMA项,如果使用了季节性差异,则后一种情况很可能发生,如果数据具有稳定和合乎逻辑的季节性模式。如果没有使用季节性差异,前者很可能会发生,只有当季节性模式不稳定时才适用。应该尽量避免在同一模型中使用多于一个或两个季节性参数(SAR + SMA),因为这可能导致过度拟合数据和/或估算中的问题。

参考链接: http://people.duke.edu/~rnau/arimrule.htm

创建模型并进行预测

经过上面的分析,可以独处需要制作的模型参数为(0,1,0)x(1,1,1,12):(说实话我也不清楚这个参数是怎么确定的,还需要继续学习, SARIMAX怎么用也还没学习明白)

mod = sm.tsa.statespace.SARIMAX(df['riders'], trend='n', order=(0,1,0), seasonal_order=(1,1,1,12))
results = mod.fit()
print(results.summary())
                                 Statespace Model Results                                 
==========================================================================================
Dep. Variable:                             riders   No. Observations:                  114
Model:             SARIMAX(0, 1, 0)x(1, 1, 1, 12)   Log Likelihood                -501.340
Date:                            Fri, 16 Nov 2018   AIC                           1008.680
Time:                                    14:13:15   BIC                           1016.526
Sample:                                01-01-1973   HQIC                          1011.856
                                     - 06-01-1982                                         
Covariance Type:                              opg                                         
==============================================================================
                 coef    std err          z      P>|z|      [0.025      0.975]
------------------------------------------------------------------------------
ar.S.L12       0.3236      0.186      1.739      0.082      -0.041       0.688
ma.S.L12      -0.9990     43.079     -0.023      0.981     -85.433      83.435
sigma2       984.7897   4.23e+04      0.023      0.981   -8.19e+04    8.39e+04
===================================================================================
Ljung-Box (Q):                       36.56   Jarque-Bera (JB):                 4.81
Prob(Q):                              0.63   Prob(JB):                         0.09
Heteroskedasticity (H):               1.48   Skew:                             0.38
Prob(H) (two-sided):                  0.26   Kurtosis:                         3.75
===================================================================================
 
Warnings:
[1] Covariance matrix calculated using the outer product of gradients (complex-step).

预测值与真实值比较:

df['forecast'] = results.predict(start = 102, end= 114, dynamic= True)  
df[['riders', 'forecast']].plot(figsize=(12, 6)) 
plt.savefig('ts_df_predict.png', bbox_inches='tight')

时间序列预测:使用Python创建季节性ARIMA模型

npredict =df['riders']['1982'].shape[0]
fig, ax = plt.subplots(figsize=(12,6))
npre = 12
ax.set(title='Ridership', xlabel='Date', ylabel='Riders')
ax.plot(df.index[-npredict-npre+1:], df.ix[-npredict-npre+1:, 'riders'], 'o', label='Observed')
ax.plot(df.index[-npredict-npre+1:], df.ix[-npredict-npre+1:, 'forecast'], 'g', label='Dynamic forecast')
legend = ax.legend(loc='lower right')
legend.get_frame().set_facecolor('w')
# plt.savefig('ts_predict_compare.png', bbox_inches='tight')

时间序列预测:使用Python创建季节性ARIMA模型

为了产生针对未来的预测值,我们加入新的时间:

start = datetime.datetime.strptime("1982-07-01", "%Y-%m-%d")
date_list = [start + relativedelta(months=x) for x in range(0,12)]
future = pd.DataFrame(index=date_list, columns= df.columns)
df = pd.concat([df, future])

在新加入的时间上来预测未来值:

df['forecast'] = results.predict(start = 114, end = 125, dynamic= True)  
df[['riders', 'forecast']].ix[-24:].plot(figsize=(12, 8)) 
#plt.savefig('ts_predict_future.png', bbox_inches='tight')

时间序列预测:使用Python创建季节性ARIMA模型

参考链接: http://www.seanabu.com/2016/03/22/time-series-seasonal-ARIMA-model-in-python/


以上所述就是小编给大家介绍的《时间序列预测:使用Python创建季节性ARIMA模型》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

精通Spring 4.x

精通Spring 4.x

陈雄华、林开雄、文建国 / 电子工业出版社 / 2017-1-1 / CNY 128.00

Spring 4.0是Spring在积蓄4年后,隆重推出的一个重大升级版本,进一步加强了Spring作为Java领域第一开源平台的翘楚地位。Spring 4.0引入了众多Java开发者翘首以盼的基于Groovy Bean的配置、HTML 5/WebSocket支持等新功能,全面支持Java 8.0,最低要求是Java 6.0。这些新功能实用性强、易用性高,可大幅降低Java应用,特别是Java W......一起来看看 《精通Spring 4.x》 这本书的介绍吧!

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具