第4章:传统时序模型:ARIMA模型原理、SARIMA模型、模型定阶与诊断、在简单轨迹预测中的应用
说实话,很多刚入行的朋友一上来就追Transformer、LSTM这些深度学习模型。但我得说句实在话——传统时序模型,尤其是ARIMA,依然是工业界的常青树。我在做轨迹预测项目时,经常先用ARIMA跑个baseline,再上复杂模型。为什么?因为ARIMA能帮你快速理解数据的底层规律。
4.1 ARIMA模型:从直觉到数学
ARIMA,全称是自回归积分滑动平均模型。名字挺长,但拆开看就三个部分:
- AR(自回归):用过去的值预测现在的值。说白了就是“昨天的轨迹影响今天的轨迹”。
- I(差分):让非平稳数据变平稳。我遇到过很多轨迹数据,走着走着就漂移了,差分一下就好了。
- MA(滑动平均):用过去的预测误差来修正当前的预测。相当于给模型加了个“纠错机制”。
数学上,ARIMA(p,d,q)可以写成:
(1 - φ₁B - φ₂B² - ... - φₚBᵖ)(1-B)ᵈyₜ = (1 + θ₁B + θ₂B² + ... + θₙBⁿ)εₜ
其中B是滞后算子,d是差分阶数。嗯,公式看着唬人,但实际用起来,你只需要关心p、d、q三个参数怎么选。
4.2 SARIMA:给模型加上季节节拍
ARIMA有个硬伤——它处理不了周期性。但轨迹数据往往有周期模式。比如,我做过一个行人轨迹项目,发现每天早晚高峰的路径模式高度相似。这时候就要上SARIMA了。
SARIMA在ARIMA基础上加了四个季节参数:P、D、Q、S。S就是周期长度。完整写法是SARIMA(p,d,q)(P,D,Q)ₛ。
举个例子,如果你发现轨迹数据每24小时重复一次模式,那S=24。模型会额外学习“今天上午9点的位置和昨天上午9点的位置有什么关系”。
# SARIMA模型示例(Python伪代码)
from statsmodels.tsa.statespace.sarimax import SARIMAX
# 假设轨迹x坐标,周期为24
model = SARIMAX(trajectory_x,
order=(1,1,1), # p,d,q
seasonal_order=(1,1,1,24)) # P,D,Q,S
results = model.fit()
4.3 模型定阶:别让参数选哭你
定阶就是选p、d、q。我见过有人手动试几十组参数,太累了。这里分享我的三板斧:
- 看ACF和PACF图:ACF拖尾、PACF截尾→选AR;ACF截尾、PACF拖尾→选MA;都拖尾→ARIMA混合。
- 用AIC/BIC准则:让计算机帮你搜。AIC越小越好,但别过拟合。我一般限制p和q不超过5。
- 差分阶数d:做单位根检验(ADF检验)。p值大于0.05就继续差分,直到平稳。
| ACF形态 | PACF形态 | 推荐模型 |
|---|---|---|
| 拖尾(缓慢衰减) | p阶后截尾 | AR(p) |
| q阶后截尾 | 拖尾 | MA(q) |
| 拖尾 | 拖尾 | ARIMA(p,d,q) |
4.4 模型诊断:残差里藏着真相
模型建好了,别急着用。先做诊断。我一般检查三件事:
- 残差是否白噪声:用Ljung-Box检验。p值大于0.05,说明残差没有自相关性,模型提取了所有信息。
- 残差是否正态分布:画QQ图。偏离太远说明模型有偏差。
- 残差是否异方差:看残差图。如果波动幅度随时间变化,说明模型没捕捉到波动率变化。
# 残差诊断代码
residuals = results.resid
# 1. Ljung-Box检验
from statsmodels.stats.diagnostic import acorr_ljungbox
lb_test = acorr_ljungbox(residuals, lags=[10])
print('p值:', lb_test['lb_pvalue'].values[0])
# 2. 画QQ图
import scipy.stats as stats
stats.probplot(residuals, dist="norm", plot=plt)
如果诊断没通过,别慌。试试调整参数,或者换模型。我有个项目,ARIMA诊断一直不过,后来发现是数据里有异常值,清洗后就好了。
4.5 在简单轨迹预测中的应用
好了,理论讲完了,咱们来点实战。假设你有一段二维轨迹数据,记录了某个物体在x和y方向上的位置。我们分别对x和y建ARIMA模型。
import pandas as pd
import numpy as np
from statsmodels.tsa.arima.model import ARIMA
import matplotlib.pyplot as plt
# 模拟轨迹数据(x方向)
np.random.seed(42)
t = np.linspace(0, 100, 200)
x_traj = 0.5 * t + np.sin(0.1 * t) + np.random.normal(0, 0.2, 200)
# 划分训练集和测试集
train = x_traj[:160]
test = x_traj[160:]
# 定阶:先用简单模型
model = ARIMA(train, order=(2,1,2))
results = model.fit()
# 预测未来40步
forecast = results.forecast(steps=40)
# 评估
from sklearn.metrics import mean_absolute_error
mae = mean_absolute_error(test, forecast)
print(f'MAE: {mae:.3f}')
# 可视化
plt.plot(test, label='真实轨迹')
plt.plot(forecast, label='ARIMA预测', linestyle='--')
plt.legend()
最后说句掏心窝的话:ARIMA不是万能的,但它是一个极好的起点。你想想看,如果连ARIMA都跑不好,直接上Transformer大概率也是白给。先打好基础,再追求花活,这是我做了这么多年时序项目最深的体会。