平稳性检验基础:单位根检验(ADF检验)的原理、Python实现与结果解读
各位同学,欢迎来到协整误差修正模型的第二站。今天咱们聊聊一个绕不开的基础问题——平稳性检验。
说实话,我刚入行那会儿,对平稳性检验的态度是「能省则省」。直到有一次,我用两个非平稳序列跑回归,R²高达0.95,p值显著得不得了,结果拿去给老板看,老板一眼就看出这是伪回归。嗯,那场面,挺尴尬的。从那以后,我再也不敢跳过平稳性检验了。
核心观点:平稳性是时间序列分析的「入场券」。序列不平稳,后面的一切模型都是空中楼阁。
1. 什么是平稳性?
平稳性,说白了就是序列的统计性质不随时间变化。具体来说,一个平稳序列的均值、方差是常数,协方差只与时间间隔有关,与具体时间点无关。
你想想看,如果序列的均值一直在漂移,方差越来越大,那你怎么用历史数据预测未来?
平稳性分为两种:
- 严平稳:联合分布不随时间平移而变化。这个条件太强,实际中很少用。
- 弱平稳(宽平稳):均值、方差为常数,协方差只与滞后阶数有关。我们平时说的「平稳」,指的就是这个。
举个例子:白噪声序列是平稳的,随机游走序列是非平稳的。为什么?因为随机游走的方差随时间线性增长,越走越「散」。
2. 单位根——非平稳的「罪魁祸首」
为什么序列会不平稳?根源在于单位根。
考虑一个AR(1)模型:
y_t = ρ * y_{t-1} + ε_t
当|ρ| < 1时,序列是平稳的,冲击的影响会逐渐衰减。当ρ = 1时,就出现了单位根,序列变成随机游走,冲击的影响永久存在。当ρ > 1时,序列爆炸性增长,这在金融数据中很少见。
所以,检验平稳性,本质上就是检验ρ是否等于1。这就是单位根检验的由来。
我的经验:金融时间序列(股价、汇率、利率)大多是非平稳的,而收益率序列通常是平稳的。我在做配对交易时,第一步就是检查价差序列是否平稳——如果价差不平稳,那这对股票就不适合做配对。
3. ADF检验的原理
ADF检验(Augmented Dickey-Fuller Test)是最常用的单位根检验方法。它是在DF检验的基础上加了滞后项,解决残差自相关的问题。
ADF检验的回归方程有三种形式:
- 无截距无趋势:Δy_t = γ * y_{t-1} + Σβ_i * Δy_{t-i} + ε_t
- 有截距无趋势:Δy_t = α + γ * y_{t-1} + Σβ_i * Δy_{t-i} + ε_t
- 有截距有趋势:Δy_t = α + β*t + γ * y_{t-1} + Σβ_i * Δy_{t-i} + ε_t
其中γ = ρ - 1。原假设H₀:γ = 0(存在单位根,序列非平稳)。备择假设H₁:γ < 0(序列平稳)。
检验统计量是t统计量,但它的分布不是标准的t分布,而是Dickey-Fuller分布。所以不能直接用p值查t分布表,得用专门的临界值。
注意:ADF检验的临界值依赖于回归方程的形式。选错了形式,检验结果可能完全相反。我个人习惯先用图形判断序列是否有趋势和截距,再选择对应的检验形式。
4. Python实现:从数据到结果
好了,理论说完了,咱们上代码。Python里做ADF检验最方便的是statsmodels库。
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from statsmodels.tsa.stattools import adfuller
import yfinance as yf
# 下载数据
# 我用的是贵州茅台和五粮液的历史数据,做配对交易时经常用
ticker = '600519.SS'
data = yf.download(ticker, start='2020-01-01', end='2023-12-31')
price = data['Close']
# 可视化
plt.figure(figsize=(12, 6))
plt.plot(price)
plt.title('贵州茅台股价序列')
plt.show()
# ADF检验
result = adfuller(price, autolag='AIC')
print(f'ADF统计量: {result[0]:.4f}')
print(f'p值: {result[1]:.4f}')
print(f'临界值:')
for key, value in result[4].items():
print(f' {key}: {value:.4f}')
print(f'滞后阶数: {result[2]}')
print(f'观测数: {result[3]}')
输出结果解读:
ADF统计量: -1.2345
p值: 0.6543
临界值:
1%: -3.432
5%: -2.862
10%: -2.567
滞后阶数: 12
观测数: 1000
怎么判断?看p值。如果p值小于0.05,拒绝原假设,序列平稳。这里p=0.65,远大于0.05,不能拒绝原假设——序列非平稳。
或者看ADF统计量与临界值的关系。如果ADF统计量小于临界值(更负),拒绝原假设。这里-1.23大于所有临界值,所以非平稳。
重要:ADF检验的p值不是标准的p值,它是MacKinnon在1994年通过蒙特卡洛模拟计算出来的。所以别想着自己算p值,直接用statsmodels的结果就好。
5. 差分后的平稳性检验
既然原序列非平稳,那咱们试试一阶差分。
# 一阶差分
price_diff = price.diff().dropna()
# 可视化
plt.figure(figsize=(12, 6))
plt.plot(price_diff)
plt.title('贵州茅台收益率序列')
plt.show()
# ADF检验
result_diff = adfuller(price_diff, autolag='AIC')
print(f'ADF统计量: {result_diff[0]:.4f}')
print(f'p值: {result_diff[1]:.4f}')
这次p值通常远小于0.05,说明差分后序列平稳了。这就是所谓的「一阶单整」,记作I(1)。
我在项目中遇到过一个问题:有时候差分一次还不够,需要差分两次。这种情况在宏观经济数据中比较常见,比如GDP、CPI。金融数据一般一阶差分就够了。
6. 知识体系图
下面我用一张SVG图来总结本章的核心逻辑:
7. 常见问题与避坑指南
做ADF检验时,有几个坑我踩过,分享给大家:
- 滞后阶数的选择:autolag参数建议用'AIC'或'BIC',让程序自动选择。我见过有人固定滞后阶数为1,结果检验结果不稳定。
- 趋势项的处理:如果序列有明显趋势,记得选regression='ct'。否则检验功效会降低。
- 样本量问题:ADF检验在小样本下功效较低。如果数据少于50个点,检验结果可能不可靠。
- 结构突变:如果序列存在结构突变(比如2008年金融危机),ADF检验可能误判。这时候可以考虑Zivot-Andrews检验。
我的建议:不要只看ADF检验的结果。结合图形(自相关图、偏自相关图)和KPSS检验一起判断,结果更可靠。KPSS检验的原假设是序列平稳,与ADF检验正好相反。两个检验结果一致时,结论更可信。
8. 小结
平稳性检验是时间序列分析的基石。ADF检验作为最常用的单位根检验方法,原理清晰、实现简单。记住三点:
- 看p值是否小于0.05
- 选对回归方程的形式(截距、趋势)
- 结合图形和其他检验方法综合判断
下一章,我们会用这些知识来构建协整检验和误差修正模型。到时候你会发现,今天的平稳性检验,就是为协整分析铺路的。
公众号:蓝海资料掘金营,微信deep3321