跳转至

12.4   自回归积分滑动平均模型

小率已经会看趋势、季节和差分了。现在他想把这些判断拼成一个能预测未来销量的模型。均哥拿出四张卡片:AR、I、MA、季节。

图 12.4.1 用 AR、I、MA 和季节拼出预测模型

ARIMA 这个名字好吓人,是不是很复杂?
拆开就不吓人:AR 看过去的值,I 先差分,MA 看过去的预测误差。

12.4.1   三个字母各管一件事

ARIMA 是 Autoregressive Integrated Moving Average 的缩写。

图 12.4.2 ARIMA 的三块积木

ARIMA\((p,d,q)\) 中:

  • \(p\):AR 阶数,使用多少个过去的观测值。
  • \(d\):差分次数,让序列更接近平稳。
  • \(q\):MA 阶数,使用多少个过去的预测误差。

一个简单的 AR(1) 可以写作:

\[ y_t = c + \phi_1 y_{t-1} + \varepsilon_t \]

如果先做一次差分,再对差分后的序列建 ARMA 模型,就进入 ARIMA 的思路。

12.4.2   ACF 和 PACF 帮我们猜阶数

ACF 和 PACF 不是万能答案,但能给定阶提供线索:

图形线索 常见提示
ACF 缓慢衰减 可能还没平稳,需要差分
PACF 在某阶后明显截尾 可能需要 AR 项
ACF 在某阶后明显截尾 可能需要 MA 项
季节滞后处有峰 可能需要季节项

定阶不要只靠肉眼

先用图形提出候选模型,再用 AIC/BIC、残差自相关和预测回测来筛选。

12.4.3   季节 ARIMA 把周期也放进模型

如果奶茶销量有周周期或月度数据有年周期,可以用 SARIMA:

\[ \operatorname{SARIMA}(p,d,q)(P,D,Q)_s \]

其中 \(s\) 是周期长度。月度数据的年周期常取 \(s=12\),周数据若有年度周期可取 \(s=52\)

import numpy as np
import pandas as pd
from statsmodels.tsa.statespace.sarimax import SARIMAX

rng = np.random.default_rng(12)
dates = pd.date_range("2018-01-01", periods=96, freq="MS")
t = np.arange(len(dates))
y = pd.Series(
    200 + 1.8 * t + 18 * np.sin(2 * np.pi * t / 12) + rng.normal(0, 5, len(t)),
    index=dates,
    name="月销量",
)

model = SARIMAX(
    y,
    order=(1, 1, 1),
    seasonal_order=(0, 1, 1, 12),
    enforce_stationarity=False,
    enforce_invertibility=False,
)
fit = model.fit(disp=False)
print("AIC:", round(fit.aic, 2))
print(fit.forecast(6).round(1))

完整脚本见:

docs/assets/scripts/ch12_time_series/04_arima/main.py

12.4.4   残差检查决定模型能不能交卷

拟合完 ARIMA 之后,别只看预测线。残差应该像白噪声:没有明显趋势、没有强自相关、没有系统性漏掉的周期。

ARIMA 不是自动预测机

阶数选得漂亮,不代表预测一定好。时间序列模型必须做滚动回测,尤其不能用未来数据参与训练。

小率的笔记本

ARIMA = AR + I + MA。
AR 看过去的值,I 负责差分,MA 看过去的误差。
季节明显时,考虑 SARIMA。
模型拟合后一定要查残差和回测表现。