7天微课程day6——用ARIMA模型进行时间序列预测

声明:

  1. 本文是系列课程的第6课
  2. 本文是对机器学习网站课程的翻译
  3. 尊重原作者,尊重知识分享

用ARIMA模型进行时间序列预测

ARIMA(AutoRegressive Intergrated Moving Average)是一个非常非常流行的时间序列预测模型。

通过本文,你将了解:

  • 简单了解ARIMA的原理
  • ARIMA如何学习时间序列并做出预测
  • ARIMA的调优

ARIMA

ARIMA可以看做几个用于时间序列预测的模型的合并,它考虑了时间序列中集中标准的分布模式,提供了简单而高效的模型。ARIMA有以下几部分组成:

  • AR: Autoregression.自回归模型建立当前预测与先前值的关系。
  • I: Intergrated. 表示加入了差分运算,用于表征时间序列的趋势。通过差分可以去除时间序列的上升或下降的趋势,从而得到平稳序列。
  • MA: Moving Average. 移动平均模型,考虑的是当前值的预测与先前时刻的残差有关。

这三个部分各有一个参数,通常表示为ARIMA(p, d, q). p, d, q取值皆为整数,三个参数的意义分别如下:

  • p: 对应AR,表示考虑的先前时刻的多少,称为滞后值。
  • d: 对应I, 表示差分阶数。
  • q: 对应MA,表示移动窗口的大小,也称为移动窗口值。

Shampoo Sales Dataset

该数据集是3年内洗发水的月销量,详见download

from pandas import read_csv
from pandas import datetime
from matplotlib import pyplot

def parser(x):
    return datetime.strptime('190'+x, '%Y-%m')

series = read_csv('shampoo-sales.csv', header=0, parse_dates=[0], index_col=0, squeeze=True, date_parser=parser)
print(series.head())
series.plot()
pyplot.show()
'''output
Month
1901-01-01 266.0
1901-02-01 145.9
1901-03-01 183.1
1901-04-01 119.3
1901-05-01 180.3
Name: Sales, dtype: float64
'''


可以看到洗发水的销量有一个明显的上升趋势。说明我们至少需要一阶差分来使数据变平稳,即d=1.

我们在看一下时间序列的自相关性。

from pandas import read_csv
from pandas import datetime
from matplotlib import pyplot
from pandas.tools.plotting import autocorrelation_plot

def parser(x):
    return datetime.strptime('190'+x, '%Y-%m')

series = read_csv('shampoo-sales.csv', header=0, parse_dates=[0], index_col=0, squeeze=True, date_parser=parser)
autocorrelation_plot(series)
pyplot.show()


可以看到过去5天的自相关性较强,大于0.5,即p=5.

现在,我们初步确定了参数p和d的值,可以先构造一个p=5d=1的ARIMA,再观察残差项以确定参数q的值。

ARIMA实践

Python中有statsmodel来创建ARIMA模型,具体步骤:

  1. ARIMA()定义模型,同时传入参数p, d, q
  2. fit()训练模型
  3. predict()预测

下面我们将训练一个ARIMA模型,并观察它的残差已制定后面的参数q。经过前面可视化分析,我们首先选用ARIMA(5, 1, 0)。

from pandas import read_csv
from pandas import datetime
from pandas import DataFrame
from statsmodels.tsa.arima_model import ARIMA
from matplotlib import pyplot

def parser(x):
    return datetime.strptime('190'+x, '%Y-%m')

series = read_csv('shampoo-sales.csv', header=0, parse_dates=[0], index_col=0, squeeze=True, date_parser=parser)

# fit model
model = ARIMA(series, order=(5, 1, 0))
model_fit = model.fit(disp=0)  # disp=0关闭对训练信息的打印
print(model_fit.summary())

# plot residual errors
residuals = DataFrame(model_fit.resid)
residuals.plot()
pyplot.show()
residuals.plot(kind='kde')
pyplot.show()
print(residuals.describe())
'''output
                             ARIMA Model Results
==============================================================================
Dep. Variable:                D.Sales   No. Observations:                   35
Model:                 ARIMA(5, 1, 0)   Log Likelihood                -196.170
Method:                       css-mle   S.D. of innovations             64.241
Date:                Mon, 12 Dec 2016   AIC                            406.340
Time:                        11:09:13   BIC                            417.227
Sample:                    02-01-1901   HQIC                           410.098
                         - 12-01-1903
=================================================================================
                    coef    std err          z      P>|z|      [95.0% Conf. Int.]
---------------------------------------------------------------------------------
const            12.0649      3.652      3.304      0.003         4.908    19.222
ar.L1.D.Sales    -1.1082      0.183     -6.063      0.000        -1.466    -0.750
ar.L2.D.Sales    -0.6203      0.282     -2.203      0.036        -1.172    -0.068
ar.L3.D.Sales    -0.3606      0.295     -1.222      0.231        -0.939     0.218
ar.L4.D.Sales    -0.1252      0.280     -0.447      0.658        -0.674     0.424
ar.L5.D.Sales     0.1289      0.191      0.673      0.506        -0.246     0.504
                                    Roots
=============================================================================
                 Real           Imaginary           Modulus         Frequency
-----------------------------------------------------------------------------
AR.1           -1.0617           -0.5064j            1.1763           -0.4292
AR.2           -1.0617           +0.5064j            1.1763            0.4292
AR.3            0.0816           -1.3804j            1.3828           -0.2406
AR.4            0.0816           +1.3804j            1.3828            0.2406
AR.5            2.9315           -0.0000j            2.9315           -0.0000
-----------------------------------------------------------------------------

count   35.000000
mean    -5.495213
std     68.132882
min   -133.296597
25%    -42.477935
50%     -7.186584
75%     24.748357
max    133.237980
'''

从表中可以看到ARIMA用于AR的常量系数和其他5个系数。
还有一个关于残差的图。


可以看到残差还有一个明显的趋势,这正是MA模型要解决的问题。
残差值的分布图如下:

在该图中可以发现残差并不是正态分布,有一定的偏离,有一点不对称,说明残差中还有噪声之外的信息。这点从 residuals.discribe()的输出中也可以看得出来。

值得一提的是,在上面的例子中我们只是为了观察residual的情况,所以没有必要划分训练集和测试集。

ARIMA模型的预测

fit()后的ARIMA模型的返回值是ARIMAResults对象,对该对象调用predict()可以进行预测。predict()接受时刻 t t <script type="math/tex" id="MathJax-Element-1">t</script>的序列作为参数。

例如,假设我们训练集的时间序列有100个观测值,若要预测下一时刻的输出,则调用predict(start=101, end=101)会返回一个shape=(1,)的数组。

predict()还有一个参数typ需要指定,若typ='linear',输出差分值;若typ='levels,输出预测值。Fortunately,在做一步预测时,我们可以用forecast()来代替predict(),就不需要那么多参数要考虑了。

这里采用的预测方式依然是walk-forward。walk-forward每一步都要加入新的观测值,那我们就每一步都re-create ARIMA模型。

from pandas import read_csv
from pandas import datetime
from matplotlib import pyplot
from statsmodels.tsa.arima_model import ARIMA
from sklearn.metrics import mean_squared_error

def parser(x):
    return datetime.strptime('190'+x, '%Y-%m')

series = read_csv('shampoo-sales.csv', header=0, parse_dates=[0], index_col=0, squeeze=True, date_parser=parser)
X = series.values
size = int(len(X) * 0.66)
train, test = X[0:size], X[size:len(X)]
history = [x for x in train]
predictions = list()

for t in range(len(test)):
    model = ARIMA(history, order=(5, 1, 0))
    model_fit = model.fit(disp=0)
    output = model_fit.forecast()
    yhat = output[0]
    predictions.append(yhat)
    obs = test[t]
    history.append(obs)
    print('predicted=%f, expected=%f' % (yhat, obs))
error = mean_squared_error(test, predictions)
print('Test MSE: %.3f' % error)
# plot
pyplot.plot(test)
pyplot.plot(predictions, color='red')
pyplot.show()
'''output
predicted=349.117688, expected=342.300000
predicted=306.512968, expected=339.700000
predicted=387.376422, expected=440.400000
predicted=348.154111, expected=315.900000
predicted=386.308808, expected=439.300000
predicted=356.081996, expected=401.300000
predicted=446.379501, expected=437.400000
predicted=394.737286, expected=575.500000
predicted=434.915566, expected=407.600000
predicted=507.923407, expected=682.000000
predicted=435.483082, expected=475.300000
predicted=652.743772, expected=581.300000
predicted=546.343485, expected=646.900000
Test MSE: 6958.325
'''

ARIMA调优

ARIMA调优的经典策略是Box-Jenkins Methodology
如果时间序列较小的话,grid searching也是一个不错的方法。

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值