Python Statsmodels:使用ARIMA模型进行时间序列分析帮助

11

我使用statsmodels中的ARIMA模型输出的结果不准确。我想知道是否有人能够帮助我理解我的代码存在什么问题。

以下是示例:

import pandas as pd
import numpy as np
import datetime as dt
from statsmodels.tsa.arima_model import ARIMA

# Setting up a data frame that looks twenty days into the past,
# and has linear data, from approximately 1 through 20
counts = np.arange(1, 21) + 0.2 * (np.random.random(size=(20,)) - 0.5)
start = dt.datetime.strptime("1 Nov 01", "%d %b %y")
daterange = pd.date_range(start, periods=20)
table = {"count": counts, "date": daterange}
data = pd.DataFrame(table)
data.set_index("date", inplace=True)

print data

               count
date
2001-11-01   0.998543
2001-11-02   1.914526
2001-11-03   3.057407
2001-11-04   4.044301
2001-11-05   4.952441
2001-11-06   6.002932
2001-11-07   6.930134
2001-11-08   8.011137
2001-11-09   9.040393
2001-11-10  10.097007
2001-11-11  11.063742
2001-11-12  12.051951
2001-11-13  13.062637
2001-11-14  14.086016
2001-11-15  15.096826
2001-11-16  15.944886
2001-11-17  17.027107
2001-11-18  17.930240
2001-11-19  18.984202
2001-11-20  19.971603

剩下的代码设置了ARIMA模型。

# Setting up ARIMA model
order = (2, 1, 2)
model = ARIMA(data, order, freq='D')
model = model.fit()
print model.predict(1, 20)

2001-11-02    1.006694
2001-11-03    1.056678
2001-11-04    1.116292
2001-11-05    1.049992
2001-11-06    0.869610
2001-11-07    1.016006
2001-11-08    1.110689
2001-11-09    0.945190
2001-11-10    0.882679
2001-11-11    1.139272
2001-11-12    1.094019
2001-11-13    0.918182
2001-11-14    1.027932
2001-11-15    1.041074
2001-11-16    0.898727
2001-11-17    1.078199
2001-11-18    1.027331
2001-11-19    0.978840
2001-11-20    0.943520
2001-11-21    1.040227
Freq: D, dtype: float64

你可以看到,数据只是在 1左右波动,而没有上升。我做错了什么?

(附带说明,由于某些原因,我无法将字符串日期 "2001-11-21"传递给预测函数。了解原因会很有帮助。)


2
尝试在预测中添加 typ='level'。请参阅 https://dev59.com/Borda4cB1Zd3GeqPOZv8 和 predict docstring。也可以直接向模型添加趋势(目前是拟合)。 - Josef
谢谢!那解决了我的问题。不过,我承认我不理解ARIMA.predict的文档说明。这可能是统计学中的一个概念。 - hlin117
2
typ='levels',而不是type='level'。也许过去是'level',但文档显示typ : str {‘linear’, ‘levels’} - Jarad
1个回答

10

简而言之

predict 方法的使用返回的是差分后的内生变量的线性预测,而不是原始内生变量的水平预测

要改变这种行为,您必须使用 typ='levels' 参数来调用 predict 方法:

preds = fit.predict(1, 30, typ='levels')

请参阅 ARIMAResults.predict 的文档以获取详细信息。

逐步操作

数据集

我们加载您在MCVE中提供的数据:

import io
import pandas as pd

raw = io.StringIO("""date        count
2001-11-01   0.998543
2001-11-02   1.914526
2001-11-03   3.057407
2001-11-04   4.044301
2001-11-05   4.952441
2001-11-06   6.002932
2001-11-07   6.930134
2001-11-08   8.011137
2001-11-09   9.040393
2001-11-10  10.097007
2001-11-11  11.063742
2001-11-12  12.051951
2001-11-13  13.062637
2001-11-14  14.086016
2001-11-15  15.096826
2001-11-16  15.944886
2001-11-17  17.027107
2001-11-18  17.930240
2001-11-19  18.984202
2001-11-20  19.971603""")

data = pd.read_fwf(raw, parse_dates=['date'], index_col='date')

正如我们所预期的那样,数据是自相关的:

from pandas.plotting import autocorrelation_plot
autocorrelation_plot(data)

enter image description here

模型与训练

我们为给定的设置 (P,D,Q) 创建一个 ARIMA 模型 对象,并使用 fit 方法对我们的数据进行训练:

from statsmodels.tsa.arima_model import ARIMA

order = (2, 1, 2)
model = ARIMA(data, order, freq='D')
fit = model.fit()

它返回一个ARIMAResults对象,这是一个重要的内容。我们可以检查模型的质量:
fit.summary()

                            ARIMA Model Results                              
==============================================================================
Dep. Variable:                D.count   No. Observations:                   19
Model:                 ARIMA(2, 1, 2)   Log Likelihood                  25.395
Method:                       css-mle   S.D. of innovations              0.059
Date:                Fri, 18 Jan 2019   AIC                            -38.790
Time:                        07:54:36   BIC                            -33.123
Sample:                    11-02-2001   HQIC                           -37.831
                         - 11-20-2001                                         
==============================================================================
                  coef    std err          z      P>|z|      [0.025     0.975]
------------------------------------------------------------------------------
const           1.0001      0.014     73.731      0.000       0.973      1.027
ar.L1.D.count  -0.3971      0.295     -1.346      0.200      -0.975      0.181
ar.L2.D.count  -0.6571      0.230     -2.851      0.013      -1.109     -0.205
ma.L1.D.count   0.0892      0.208      0.429      0.674      -0.318      0.496
ma.L2.D.count   1.0000      0.640      1.563      0.140      -0.254      2.254
                                    Roots                                    
==============================================================================
                   Real          Imaginary           Modulus         Frequency
------------------------------------------------------------------------------
AR.1            -0.3022           -1.1961j            1.2336           -0.2894
AR.2            -0.3022           +1.1961j            1.2336            0.2894
MA.1            -0.0446           -0.9990j            1.0000           -0.2571
MA.2            -0.0446           +0.9990j            1.0000            0.2571
------------------------------------------------------------------------------

我们可以大致估计残差是如何分布的:

residuals = pd.DataFrame(fit.resid, columns=['residuals'])
residuals.plot(kind='kde')

enter image description here

预测

如果我们对模型满意,那么我们可以对一些样本内或样本外的数据进行预测。

可以使用 predict 方法来完成此操作,默认情况下该方法返回 差分内生变量而不是 内生变量本身。要更改此行为,我们必须指定 typ='levels'

preds = fit.predict(1, 30, typ='levels')

然后我们的预测结果与我们的训练数据具有相同的水平:

enter image description here

此外,如果我们也希望有置信区间,那么我们可以使用forecast方法。

字符串参数

您还可以使用字符串(如果想避免麻烦,请始终使用ISO-8601格式)或datetime对象来提供predict

preds = fit.predict("2001-11-02", "2001-12-15", typ='levels')

在StatsModels 0.9.0上按预期工作:

import statsmodels as sm
sm.__version__ # '0.9.0'

默认使用“linear”而不是“levels”的明显原因是什么?为什么这更自然? - Raul Guarini Riva

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接