时间序列分析基础:平稳性检验、自相关与偏自相关函数、ARIMA模型原理与建模流程
各位同学,欢迎来到第四章。前面我们聊了碳交易数据的获取和预处理,今天要啃的这块骨头,是时间序列分析的核心地基。说白了,如果你不懂平稳性、ACF/PACF和ARIMA,那后面所有的预测模型都像在沙滩上盖楼,风一吹就倒。
我个人习惯,在开始任何预测之前,先花70%的时间去理解数据的内在结构。碳价格数据尤其如此——它受政策、季节、能源价格多重影响,噪声极大。今天我们就一步步拆解,把时间序列的“脾气”摸透。
4.1 平稳性检验:为什么它如此重要?
先问一个问题:一个随机游走的股票价格,和一个均值回归的债券收益率,哪个更容易预测?答案是后者。因为它的统计性质——均值、方差——不会随时间剧烈漂移。这就是平稳性的核心。
什么是平稳性?
严格来说,一个时间序列是平稳的,意味着它的统计特性(均值、方差、自协方差)不随时间变化。但在实际项目中,我们通常只要求“弱平稳”或“宽平稳”:
- 均值恒定:序列围绕一个固定水平波动,没有趋势。
- 方差恒定:波动幅度不随时间变化,没有明显的“喇叭口”形状。
- 自协方差只与时间间隔有关:比如相隔1天的两个观测值之间的相关性,不随具体日期改变。
避坑指南:我曾经在分析欧盟碳配额(EUA)价格时,直接拿原始数据建模,结果模型预测值一路飘移,完全失效。后来才发现,2018年市场改革导致均值发生了结构性突变——这就是非平稳的典型表现。
如何检验平稳性?
最常用的方法是ADF检验(Augmented Dickey-Fuller Test)。它的原假设是“序列存在单位根(非平稳)”。如果p值小于0.05,我们就拒绝原假设,认为序列是平稳的。
# Python代码示例:ADF检验
from statsmodels.tsa.stattools import adfuller
import pandas as pd
# 假设df是包含碳价格数据的DataFrame,列名为'price'
result = adfuller(df['price'].dropna())
print(f'ADF统计量: {result[0]:.4f}')
print(f'p值: {result[1]:.4f}')
if result[1] < 0.05:
print('序列平稳,可以继续建模')
else:
print('序列非平稳,需要进行差分处理')
嗯,这里要注意:ADF检验对滞后阶数的选择比较敏感。我一般用AIC准则自动选择最优滞后阶数,而不是手动指定。
4.2 自相关与偏自相关函数:读懂数据的“记忆”
平稳性解决了“能不能建模”的问题,而ACF和PACF解决的是“用什么模型”的问题。它们就像时间序列的X光片,能让你看到数据内部的相关结构。
自相关函数(ACF)
ACF衡量的是当前观测值与过去观测值之间的相关性。比如,今天的碳价和昨天的碳价相关吗?和前天的呢?
- 如果ACF在滞后1阶后迅速截尾(突然降到0附近),说明序列可能只依赖最近一期。
- 如果ACF缓慢衰减(拖尾),说明序列有长期记忆,可能需要差分或使用AR模型。
偏自相关函数(PACF)
PACF剔除了中间变量的影响,只衡量“纯”的相关性。比如,在控制昨天碳价的影响后,今天和前天的碳价还有直接关系吗?
- 如果PACF在滞后p阶后截尾,提示使用AR(p)模型。
- 如果ACF在滞后q阶后截尾,提示使用MA(q)模型。
个人经验:我在做广东碳市场数据时,发现ACF在滞后7天和30天都有明显峰值。后来一查,原来是每周配额拍卖和每月履约报告导致的周期性。这种“业务知识+统计指标”的结合,才是真正的预测能力。
# 绘制ACF和PACF图
from statsmodels.graphics.tsaplots import plot_acf, plot_pacf
import matplotlib.pyplot as plt
# 假设data是平稳后的序列
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(10, 8))
plot_acf(data, lags=40, ax=ax1)
plot_pacf(data, lags=40, ax=ax2)
plt.show()
4.3 ARIMA模型原理与建模流程
ARIMA模型,全称是自回归积分滑动平均模型。它其实是三个组件的组合:
- AR(自回归):用过去p个时刻的值来预测当前值。说白了,就是“历史会重演”。
- I(差分):通过d次差分,把非平稳序列变成平稳序列。这是处理趋势的关键。
- MA(滑动平均):用过去q个时刻的预测误差来修正当前预测。相当于“纠错机制”。
ARIMA模型的数学表达式是:
ARIMA(p,d,q) 模型:
(1 - φ₁B - φ₂B² - ... - φₚBᵖ)(1-B)ᵈ yₜ = (1 + θ₁B + θ₂B² + ... + θₙBᵠ) εₜ
其中:
- B是滞后算子,Bᵏyₜ = yₜ₋ₖ
- φ是AR系数
- θ是MA系数
- εₜ是白噪声误差项
建模流程:四步走
- 识别阶数:通过ACF和PACF图,初步判断p和q的范围。如果ACF拖尾、PACF在p阶截尾,选AR(p);如果ACF在q阶截尾、PACF拖尾,选MA(q)。
- 参数估计:使用最大似然估计或最小二乘法,拟合模型参数。我习惯用AIC和BIC准则来比较不同(p,d,q)组合的优劣。
- 模型诊断:检查残差是否为白噪声(即残差序列的ACF应无显著相关性)。如果残差还有模式,说明模型没捕捉到全部信息。
- 预测:用拟合好的模型进行滚动预测或静态预测。
注意:我曾经犯过一个低级错误——在模型诊断阶段,只看了残差的ACF图,没做Ljung-Box检验。结果残差明明有季节性模式,我却没发现。后来加了季节性差分,模型效果才提升。所以,一定要用统计检验来验证残差的白噪声性质。
# ARIMA模型拟合示例
from statsmodels.tsa.arima.model import ARIMA
# 假设data是平稳后的序列,p=2, d=1, q=2
model = ARIMA(data, order=(2, 1, 2))
results = model.fit()
print(results.summary())
# 残差诊断
residuals = results.resid
lb_test = acorr_ljungbox(residuals, lags=[10], return_df=True)
print(lb_test)
4.4 知识体系总览
为了让你更直观地理解本章的逻辑,我画了一张流程图。它展示了从原始数据到ARIMA模型的全过程:
这张图把整个流程串起来了。你想想看,从原始数据到最终模型,每一步都有明确的判断标准。我个人习惯在每一步都打印出统计量,而不是只看图——数字不会骗人,但图可能会误导。
4.5 实战中的常见陷阱
| 陷阱 | 表现 | 解决方案 |
|---|---|---|
| 过度差分 | 序列方差变大,出现负自相关 | 先做一次差分,再检验平稳性;不要盲目差分 |
| 忽略季节性 | ACF在固定滞后阶数(如7、30)有显著峰值 | 使用SARIMA模型,加入季节性差分 |
| 模型过拟合 | 训练集表现极好,测试集一塌糊涂 | 用AIC/BIC选择简约模型,避免p、q过大 |
| 忽视结构性突变 | 模型在某个时间点后预测偏差越来越大 | 使用Chow检验检测突变点,分段建模 |
一个小技巧:当你拿到新的碳价数据时,先画一个时间序列图。如果看到明显的“断崖”或“跳升”,大概率是政策事件导致的。这时候不要急着建模,先做事件标注,再考虑是否要分段处理。
好了,这一章的内容就到这里。平稳性检验、ACF/PACF、ARIMA建模,这三板斧是时间序列分析的基石。下一章我们会把这些工具应用到真实的碳交易数据中,看看它们到底能发挥多大威力。