使用python建立ARIMA模型

案例:2015/1/1至2015/2/6某餐厅销售数据进行建模
参考链接:
1.https://zhuanlan.zhihu.com/p/54985638
2.https://zhuanlan.zhihu.com/p/35128342
3.https://www.kaggle.com/pratyushakar/time-series-analysis-using-arima-sarima
statsmodels.tsa.arima_model文档:https://www.statsmodels.org/stable/search.html?q=statsmodels.tsa.arima_model
1:原始数据平稳性判断
2:差分数据平稳性判断
3:对差分数据建模,并得到预测值
4:返回原数据的预测值,并画出拟合图

import pandas as pd
import matplotlib.pyplot as plt  
from datetime import datetime   #数据索引改为时间
import numpy as np
import statsmodels.api as sm     #acf,pacf图
from statsmodels.tsa.stattools import adfuller  #adf检验
from pandas.plotting import autocorrelation_plot
from statsmodels.tsa.arima_model import ARIMA  
excelFile = 'C:/Users/admin/Desktop/Jupyter/数据分析/python数据分析-从入门到精通/第12周/arima_data.xls'
#读取数据,指定日期列为指标,Pandas自动将“日期”列识别为Datetime格式
data = pd.read_excel(excelFile, index_col = u'日期')
data = pd.DataFrame(data,dtype=np.float64)
#时序图
plt.figure(figsize=(10, 6))
plt.rcParams['font.sans-serif'] = ['SimHei']    #用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False      #用来正常显示负号
data["销量"].plot()
plt.xlabel('日期',fontsize=12,verticalalignment='top')
plt.ylabel('销量',fontsize=14,horizontalalignment='center')
plt.show()

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-M5qtJ4jt-1588034787665)(output_3_0.png)]

data.head()
销量
日期
2015-01-013023.0
2015-01-023039.0
2015-01-033056.0
2015-01-043138.0
2015-01-053188.0
fig = plt.figure(figsize=(12,8))
ax1=fig.add_subplot(211)
fig = sm.graphics.tsa.plot_acf(data,lags=20,ax=ax1)
ax2 = fig.add_subplot(212)
fig = sm.graphics.tsa.plot_pacf(data,lags=20,ax=ax2)
plt.show()

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-C6eIqeXf-1588034787768)(output_5_0.png)]

#进行ADF检验
temp = np.array(data["销量"])
t = adfuller(temp)  # ADF检验
output=pd.DataFrame(index=['Test Statistic Value', "p-value", "Lags Used", "Number of Observations Used","Critical Value(1%)","Critical Value(5%)","Critical Value(10%)"],columns=['value'])
output['value']['Test Statistic Value'] = t[0]
output['value']['p-value'] = t[1]
output['value']['Lags Used'] = t[2]
output['value']['Number of Observations Used'] = t[3]
output['value']['Critical Value(1%)'] = t[4]['1%']
output['value']['Critical Value(5%)'] = t[4]['5%']
output['value']['Critical Value(10%)'] = t[4]['10%']
output
value
Test Statistic Value1.81377
p-value0.998376
Lags Used10
Number of Observations Used26
Critical Value(1%)-3.71121
Critical Value(5%)-2.98125
Critical Value(10%)-2.63009
# p值0.998,即可以认为非平稳
#ADF检验的原假设是存在单位根,只要这个统计值是小于1%水平下的数字就可以极显著的拒绝原假设,认为数据平稳
#https://www.lizenghai.com/archives/595.html
#白噪声检验
# 白噪声检验(如果是白噪声,即纯随机序列,则没有研究的意义了。)
from statsmodels.stats.diagnostic import acorr_ljungbox
print(acorr_ljungbox(data["销量"], lags=1)) 
(array([ 32.0111333]), array([  1.53291527e-08]))
#返回统计量和p值
# 原假设是序列为白噪声,所以p值为1.53291527e-08,表明序列为非白噪声序列
#差分
data1= data["销量"].diff(1)
plt.figure(figsize=(10, 6))
data1.plot()
plt.xlabel('日期',fontsize=12,verticalalignment='top')
plt.ylabel('销量差分',fontsize=14,horizontalalignment='center')
plt.show()

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DJ1Ixpyy-1588034787770)(output_13_0.png)]

#差分序列的ADF平稳性检验
temp = np.diff(data["销量"])
t = adfuller(temp)  # ADF检验
output=pd.DataFrame(index=['Test Statistic Value', "p-value", "Lags Used", "Number of Observations Used","Critical Value(1%)","Critical Value(5%)","Critical Value(10%)"],columns=['value'])
output['value']['Test Statistic Value'] = t[0]
output['value']['p-value'] = t[1]
output['value']['Lags Used'] = t[2]
output['value']['Number of Observations Used'] = t[3]
output['value']['Critical Value(1%)'] = t[4]['1%']
output['value']['Critical Value(5%)'] = t[4]['5%']
output['value']['Critical Value(10%)'] = t[4]['10%']
output
value
Test Statistic Value-3.15606
p-value0.0226734
Lags Used0
Number of Observations Used35
Critical Value(1%)-3.63274
Critical Value(5%)-2.94851
Critical Value(10%)-2.61302
# 看到 t-statistic 的值-3.156要小于5%,所以拒绝原假设,另外,p-value的值0.02也很小。
#将差分序列改为与原始数据相同的数据格式
sales = list(np.diff(data["销量"]))
data2 = {
    "日期":data1.index[1:],  #1月1日是空值,从1月2号开始取
    "销量":sales
}
df = pd.DataFrame(data2)
df['日期'] = pd.to_datetime(df['日期']) 
#df[''date]数据类型为“object”,通过pd.to_datetime将该列数据转换为时间类型,即datetime。 
data_diff = df.set_index(['日期'], drop=True)    
#将日期设置为索引
data_diff.head()
销量
日期
2015-01-0216.0
2015-01-0317.0
2015-01-0482.0
2015-01-0550.0
2015-01-0636.0
#差分序列的acf,pacf
fig = plt.figure(figsize=(12,8))
ax1=fig.add_subplot(211)
fig = sm.graphics.tsa.plot_acf(data_diff,lags=20,ax=ax1)
ax2 = fig.add_subplot(212)
fig = sm.graphics.tsa.plot_pacf(data_diff,lags=20,ax=ax2)
plt.show()

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VxcVT32H-1588034787774)(output_20_0.png)]

#模型定阶:AIC,BIC,或者根据acf,pacf图
# 为了控制计算量,我们限制AR最大阶不超过6,MA最大阶不超过4。
sm.tsa.arma_order_select_ic(data_diff,max_ar=6,max_ma=4,ic='aic')['aic_min_order']  # AIC




    (0, 1)




```python
#BIC
#对模型进行定阶
pmax = int(len(df) / 10)    #一般阶数不超过 length /10
qmax = int(len(df) / 10)
bic_matrix = []
for p in range(pmax +1):
    temp= []
    for q in range(qmax+1):
        try:
            temp.append(ARIMA(data, (p, 1, q)).fit().bic)
        except:
            temp.append(None)
        bic_matrix.append(temp)

bic_matrix = pd.DataFrame(bic_matrix)   #将其转换成Dataframe 数据结构
p,q = bic_matrix.stack().idxmin()   #先使用stack 展平, 然后使用 idxmin 找出最小值的位置
print(u'BIC 最小的p值 和 q 值:%s,%s' %(p,q))  #  BIC 最小的p值 和 q 值:0,1
#所以可以建立ARIMA 模型,ARIMA(0,1,1)
BIC 最小的p值 和 q 值:0,1
#具体模型信息
model = ARIMA(data, (p,1,q)).fit()
model.summary2()        #生成一份模型报告
Model:ARIMABIC:422.5101
Dependent Variable:D.销量Log-Likelihood:-205.88
Date:2020-04-27 22:21Scale:1.0000
No. Observations:36Method:css-mle
Df Model:2Sample:01-02-2015
Df Residuals:3402-06-2015
Converged:1.0000S.D. of innovations:73.086
AIC:417.7595HQIC:419.418
Coef.Std.Err.tP>|t|[0.0250.975]
const49.956420.13902.48060.018210.484789.4281
ma.L1.D.销量0.67100.16484.07120.00030.34800.9941
RealImaginaryModulusFrequency
MA.1-1.49020.00001.49020.5000
predictions_ARIMA_diff = pd.Series(model.fittedvalues, copy=True)
print(predictions_ARIMA_diff.head())
日期
2015-01-02    49.956427
2015-01-03    34.245128
2015-01-04    39.803780
2015-01-05    76.789439
2015-01-06    32.393775
dtype: float64
plt.figure(figsize=(10, 6))
plt.plot(predictions_ARIMA_diff,label="forecast_diff")
plt.plot(data_diff,label="diff")
plt.xlabel('日期',fontsize=12,verticalalignment='top')
plt.ylabel('销量差分',fontsize=14,horizontalalignment='center')
plt.legend()
plt.show()

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-84bGCcTq-1588034787776)(output_28_0.png)]

#注意这里差分预测值和实际数据有日期错位,所以要进行修改
predictions = [i + j for i, j in zip(list(predictions_ARIMA_diff), list(data["销量"][:36]))]
prediction_sales = {
    "日期":data1.index[1:],
    "销量":predictions
}
prediction_sales = pd.DataFrame(prediction_sales)
prediction_sales['日期'] = pd.to_datetime(prediction_sales['日期']) 
#df[''date]数据类型为“object”,通过pd.to_datetime将该列数据转换为时间类型,即datetime。 
prediction_sales = prediction_sales.set_index(['日期'], drop=True)    
#将日期设置为索引
prediction_sales.head()
销量
日期
2015-01-023072.956427
2015-01-033073.245128
2015-01-043095.803780
2015-01-053214.789439
2015-01-063220.393775
plt.figure(figsize=(10, 6))
plt.plot(prediction_sales,label="forecast")
plt.plot(data,label="real")
plt.xlabel('日期',fontsize=12,verticalalignment='top')
plt.ylabel('销量',fontsize=14,horizontalalignment='center')
plt.legend()
plt.show()

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TgGAVe06-1588034787778)(output_32_0.png)]

model.forecast(5)   #为未来5天进行预测, 返回预测结果, 标准误差, 和置信区间
(array([ 4873.9667493 ,  4923.92317644,  4973.87960359,  5023.83603073,
         5073.79245787]),
 array([  73.08574293,  142.32679918,  187.542821  ,  223.80281869,
         254.95704265]),
 array([[ 4730.72132537,  5017.21217324],
        [ 4644.96777602,  5202.87857687],
        [ 4606.30242887,  5341.4567783 ],
        [ 4585.19056646,  5462.48149499],
        [ 4574.08583666,  5573.49907907]])
  • 55
    点赞
  • 608
    收藏
    觉得还不错? 一键收藏
  • 56
    评论
ARIMA(差分自回归移动平均模型)是一种常用的时间序列分析和预测方法,它可以用来分析和预测未来的趋势和周期性变化。在Python中,使用statsmodels包可以很方便地建立ARIMA模型。下面是一个使用Python建立ARIMA模型的示例代码: ```python import pandas as pd import numpy as np import matplotlib.pyplot as plt from statsmodels.tsa.stattools import adfuller from statsmodels.tsa.arima_model import ARIMA # 读取数据 data = pd.read_csv('data.csv', index_col=0, parse_dates=True) # 检验时间序列的平稳性 def test_stationarity(timeseries): # 计算移动平均和移动标准差 rolling_mean = timeseries.rolling(window=12).mean() rolling_std = timeseries.rolling(window=12).std() # 绘制移动平均和移动标准差图像 plt.plot(timeseries, color='blue', label='Original') plt.plot(rolling_mean, color='red', label='Rolling Mean') plt.plot(rolling_std, color='black', label='Rolling Std') plt.legend(loc='best') plt.title('Rolling Mean & Standard Deviation') plt.show() # 进行DF检验 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) # 对时间序列进行差分操作 def difference(timeseries): diff = timeseries.diff() diff.dropna(inplace=True) return diff # 建立ARIMA模型 def arima_model(timeseries): # 对时间序列进行差分操作 diff = difference(timeseries) # 检验差分后的时间序列的平稳性 test_stationarity(diff) # 选择模型参数 p = range(0, 3) d = range(0, 3) q = range(0, 3) pdq = [(x, y, z) for x in p for y in d for z in q] aic = [] for i in pdq: try: model = ARIMA(timeseries, order=i) result = model.fit(disp=0) aic.append(result.aic) except: continue index = aic.index(min(aic)) best_pdq = pdq[index] # 建立ARIMA模型并进行预测 model = ARIMA(timeseries, order=best_pdq) result = model.fit(disp=0) pred = result.predict(start='2018-01-01', end='2019-01-01', dynamic=True) # 绘制预测结果图像 plt.plot(timeseries, label='Original') plt.plot(pred, color='red', label='Predicted') plt.legend(loc='best') plt.title('ARIMA') plt.show() # 运行ARIMA模型 arima_model(data) ``` 以上代码中,我们首先使用pandas读取时间序列数据,并使用matplotlib绘制原始数据的图像,用于观察时间序列的趋势和周期性变化。接着,我们使用DF检验方法检验时间序列的平稳性,如果时间序列不平稳,我们使用差分方法将其转化为平稳时间序列。然后,我们使用ARIMA模型对时间序列进行建模和预测,最后使用matplotlib绘制预测结果图像。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 56
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值