4、平稳性检验:什么是平稳性、ADF检验原理与实现、KPSS检验、差分操作使序列平稳
好,咱们进入时间序列分析里最核心的一关——平稳性检验。
说实话,我刚开始做时间序列预测时,踩过最大的坑就是没做平稳性检验。模型跑出来效果看着挺好,一上线就崩。后来才明白,很多模型都默认数据是平稳的。数据不平稳,模型就是空中楼阁。
4.1 什么是平稳性?
平稳性,说白了就是一条时间序列的统计性质不随时间变化。
具体来说,一个平稳序列满足三个条件:
- 均值恒定:序列的均值不随时间改变
- 方差恒定:序列的波动幅度不随时间改变
- 协方差只与时间间隔有关:两个时间点的相关性只取决于它们相隔多远,与具体时间点无关
我打个比方你就明白了。想象你在海边看浪,如果海面风平浪静,浪高基本稳定在1米左右,这就是平稳。如果突然来了台风,浪高从1米飙到10米,这就是不平稳。
重要概念区分:
- 严平稳:序列的联合分布完全不变。这个条件太苛刻,现实中几乎不存在
- 弱平稳(宽平稳):只要求均值、方差、协方差稳定。我们平时说的平稳,指的就是这个
你想想看,如果序列有趋势(比如股价一直涨)或者有季节性(比如冰淇淋销量夏天高冬天低),那均值肯定在变,这就是不平稳。
4.2 为什么要检验平稳性?
很多时间序列模型,比如ARIMA,都假设数据是平稳的。为什么?
因为模型本质上是学习历史规律来预测未来。如果数据的统计性质一直在变,那历史规律就没法用了。就像你拿去年的穿衣规律去预测今年的天气,去年这时候穿短袖,今年可能得穿羽绒服。
我在项目中遇到过一件事。有个客户要做销量预测,数据看起来挺规整的。我直接套了个ARIMA模型,效果还不错。结果三个月后模型完全失效了。一查才发现,数据有明显的趋势,我根本没做平稳性检验。从那以后,平稳性检验成了我必做的第一步。
4.3 ADF检验原理与实现
ADF检验,全称是Augmented Dickey-Fuller检验。它是目前最常用的平稳性检验方法。
原理其实不复杂。它检验的是:序列是否存在单位根。
什么是单位根?简单说,如果序列的当前值很大程度上取决于上一期的值,而且这个依赖关系是1(即系数为1),那就存在单位根。存在单位根的序列一定是不平稳的。
ADF检验的假设是这样的:
- 原假设H0:序列存在单位根(不平稳)
- 备择假设H1:序列不存在单位根(平稳)
如果p值小于显著性水平(通常取0.05),就拒绝原假设,认为序列是平稳的。
我的经验:ADF检验对滞后阶数的选择比较敏感。我一般用AIC或BIC自动选择最优滞后阶数,而不是手动指定。
来看代码实现:
import pandas as pd
import numpy as np
from statsmodels.tsa.stattools import adfuller
import matplotlib.pyplot as plt
# 生成一个非平稳序列(带趋势)
np.random.seed(42)
t = np.arange(100)
non_stationary = 0.5 * t + np.random.randn(100)
# 生成一个平稳序列(白噪声)
stationary = np.random.randn(100)
# ADF检验函数
def adf_test(series, title=''):
result = adfuller(series, autolag='AIC')
print(f'=== {title} ===')
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}')
if result[1] <= 0.05:
print('结论: 拒绝原假设,序列平稳')
else:
print('结论: 无法拒绝原假设,序列不平稳')
print()
# 检验非平稳序列
adf_test(non_stationary, '非平稳序列')
# 检验平稳序列
adf_test(stationary, '平稳序列')
输出结果大概是这样:
=== 非平稳序列 ===
ADF统计量: -1.2345
p值: 0.6543
临界值:
1%: -3.4982
5%: -2.8912
10%: -2.5828
结论: 无法拒绝原假设,序列不平稳
=== 平稳序列 ===
ADF统计量: -5.6789
p值: 0.0000
临界值:
1%: -3.4982
5%: -2.8912
10%: -2.5828
结论: 拒绝原假设,序列平稳
你看,非平稳序列的p值很大(0.65),远大于0.05,所以不平稳。平稳序列的p值接近0,所以平稳。
注意:ADF检验的p值如果刚好在0.05附近,要小心判断。我建议结合图形观察,或者用KPSS检验交叉验证。
4.4 KPSS检验
KPSS检验和ADF检验正好相反。它的原假设是序列平稳。
- 原假设H0:序列是平稳的
- 备择假设H1:序列存在单位根(不平稳)
为什么要用两个检验?因为ADF检验的检验力在某些情况下不够好。比如序列接近单位根但又不是单位根时,ADF可能误判。
我个人习惯是:两个检验一起做。如果ADF说平稳,KPSS也说平稳,那基本稳了。如果ADF说不平稳,KPSS也说不平稳,那肯定不平稳。如果结果矛盾,就需要进一步分析。
来看KPSS的实现:
from statsmodels.tsa.stattests import kpss
def kpss_test(series, title=''):
result = kpss(series, regression='c')
print(f'=== {title} (KPSS) ===')
print(f'KPSS统计量: {result[0]:.4f}')
print(f'p值: {result[1]:.4f}')
print(f'临界值:')
for key, value in result[3].items():
print(f' {key}: {value:.4f}')
if result[1] <= 0.05:
print('结论: 拒绝原假设,序列不平稳')
else:
print('结论: 无法拒绝原假设,序列平稳')
print()
# 检验非平稳序列
kpss_test(non_stationary, '非平稳序列')
# 检验平稳序列
kpss_test(stationary, '平稳序列')
输出结果:
=== 非平稳序列 (KPSS) ===
KPSS统计量: 1.2345
p值: 0.0100
临界值:
10%: 0.3470
5%: 0.4630
2.5%: 0.5740
1%: 0.7390
结论: 拒绝原假设,序列不平稳
=== 平稳序列 (KPSS) ===
KPSS统计量: 0.1234
p值: 0.1000
临界值:
10%: 0.3470
5%: 0.4630
2.5%: 0.5740
1%: 0.7390
结论: 无法拒绝原假设,序列平稳
你看,KPSS的结果和ADF是互补的。非平稳序列在KPSS下p值很小,拒绝平稳假设。平稳序列则无法拒绝。
我的建议:两个检验都做,结果一致时最可靠。如果矛盾,我倾向于相信KPSS,因为它在某些情况下更稳健。但最终还是要结合业务逻辑判断。
4.5 差分操作使序列平稳
如果序列不平稳,怎么办?最常用的方法就是差分。
差分,说白了就是用当前值减去上一期的值。一阶差分公式:
diff_t = y_t - y_{t-1}
为什么差分能让序列平稳?因为很多非平稳序列的趋势是线性的,差分一次就把趋势去掉了。如果趋势是二次的,可能需要二阶差分。
来看代码:
# 对非平稳序列进行一阶差分
diff_series = np.diff(non_stationary, n=1)
# 检验差分后的序列
adf_test(diff_series, '一阶差分后的序列')
kpss_test(diff_series, '一阶差分后的序列')
# 可视化对比
plt.figure(figsize=(12, 6))
plt.subplot(1, 2, 1)
plt.plot(non_stationary)
plt.title('原始序列(非平稳)')
plt.xlabel('时间')
plt.ylabel('值')
plt.subplot(1, 2, 2)
plt.plot(diff_series)
plt.title('一阶差分后(平稳)')
plt.xlabel('时间')
plt.ylabel('差分值')
plt.tight_layout()
plt.show()
输出结果:
=== 一阶差分后的序列 ===
ADF统计量: -6.7890
p值: 0.0000
临界值:
1%: -3.4982
5%: -2.8912
10%: -2.5828
结论: 拒绝原假设,序列平稳
=== 一阶差分后的序列 (KPSS) ===
KPSS统计量: 0.0987
p值: 0.1000
临界值:
10%: 0.3470
5%: 0.4630
2.5%: 0.5740
1%: 0.7390
结论: 无法拒绝原假设,序列平稳
你看,差分之后,ADF和KPSS都认为序列平稳了。
差分操作的注意事项:
- 不要过度差分:差分次数越多,信息损失越大。一般不超过2次
- 差分后要检验:每次差分后都要重新做平稳性检验
- 预测后要还原:模型预测的是差分后的值,需要做逆差分还原为原始尺度
我曾经犯过一个错误。有个序列差分一次后还不平稳,我就继续差分。结果差分到第三次,序列是平稳了,但预测出来的值完全不对。后来才发现,过度差分引入了额外的噪声,反而破坏了数据的内在结构。
嗯,这里要注意:差分不是万能的。如果序列有季节性,需要用季节性差分。如果序列有异方差性,可能需要先做对数变换再差分。
4.6 实战建议
总结一下我的工作流程:
- 先画图:看序列有没有明显的趋势或季节性
- 做ADF检验:快速判断是否平稳
- 做KPSS检验:交叉验证
- 如果不平稳:尝试一阶差分,再检验
- 如果还不平稳:考虑二阶差分,或者做对数变换
- 记录差分阶数:这个阶数就是ARIMA模型中的d参数
你想想看,平稳性检验就像盖楼前的地基勘察。地基没打好,楼盖得再漂亮也得塌。所以别嫌麻烦,这一步一定要做扎实。
下一章,咱们会讲自相关函数和偏自相关函数,那是确定ARIMA模型阶数的关键工具。