第三讲:ADF检验实战——从原理到代码,手把手教你判断平稳性

各位同学好,欢迎来到《金融数据平稳化处理实战攻略》的第三讲。

上一讲我们聊了平稳性的直观概念,说白了就是“数据不能太飘”。但光靠眼睛看K线图,你很难判断一个序列到底稳不稳。这时候,就需要一个“裁判”来给出量化结论——ADF检验就是这个裁判。

我个人习惯把ADF检验叫做“单位根检验的黄金标准”。为什么这么说?因为它在金融时间序列分析里,几乎是必过的一关。你想想看,如果你连数据是不是平稳的都没搞清楚,后面做回归、做预测,结果很可能全是“伪回归”,那可就白忙活了。

一、ADF检验的原理:到底在测什么?

ADF检验的全称是Augmented Dickey-Fuller test,中文叫“增广迪基-福勒检验”。名字挺长,但核心思想很简单——它是在检验你的时间序列里有没有“单位根”。

什么是单位根?

我举个例子你就明白了。假设一个序列的当前值等于上一期的值加上一个随机误差:

Y_t = Y_{t-1} + ε_t

这个方程里,Y_t前面的系数是1,这就是“单位根”。有单位根的序列,就是随机游走,是非平稳的。ADF检验要做的,就是看看这个系数是不是真的等于1。

更正式一点说,ADF检验的回归方程是:

ΔY_t = α + βt + γY_{t-1} + δ₁ΔY_{t-1} + ... + δₚΔY_{t-p} + ε_t

其中:

  • ΔY_t 是Y的一阶差分
  • α 是截距项(漂移项)
  • βt 是时间趋势项
  • γ 是我们最关心的系数——如果γ=0,说明有单位根
  • δ₁到δₚ是滞后项的系数,用来消除自相关

原假设H₀:γ=0(序列有单位根,非平稳)
备择假设H₁:γ<0(序列没有单位根,平稳)

说白了,ADF检验就是在问:“这个序列是不是随机游走?”如果答案是“是”,那就不平稳;如果答案是“否”,那就平稳。

核心要点:ADF检验的p-value如果小于显著性水平(通常0.05),就拒绝原假设,认为序列是平稳的。反之,p-value大,就不能拒绝原假设,序列非平稳。

二、Python实现:一行代码搞定ADF检验

理论讲完了,咱们直接上代码。Python里做ADF检验,最常用的库是statsmodels。我个人习惯用adfuller这个函数,因为它返回的信息很全。

先安装库(如果还没装的话):

pip install statsmodels pandas numpy

然后看代码:

import pandas as pd
import numpy as np
from statsmodels.tsa.stattools import adfuller
import yfinance as yf

# 获取股票数据
ticker = 'AAPL'
data = yf.download(ticker, start='2020-01-01', end='2023-12-31')
price = data['Close']

# 执行ADF检验
result = adfuller(price, autolag='AIC')

# 提取结果
adf_statistic = result[0]
p_value = result[1]
used_lag = result[2]
nobs = result[3]
critical_values = result[4]

print(f'ADF统计量: {adf_statistic:.4f}')
print(f'p-value: {p_value:.6f}')
print(f'使用的滞后阶数: {used_lag}')
print(f'观测样本数: {nobs}')
print('临界值:')
for key, value in critical_values.items():
    print(f'  {key}: {value:.4f}')

运行这段代码,你会看到类似这样的输出:

ADF统计量: -1.2345
p-value: 0.6543
使用的滞后阶数: 10
观测样本数: 1000
临界值:
  1%: -3.4369
  5%: -2.8643
  10%: -2.5683

嗯,这里要注意:p-value是0.65,远大于0.05。说明什么?说明我们不能拒绝原假设,这个序列有单位根,是非平稳的。这其实符合直觉——股票价格通常是非平稳的。

小技巧:参数autolag='AIC'表示自动选择最优滞后阶数,基于AIC准则。我个人建议一直用这个设置,省心又准确。如果你非要手动设,可以用maxlag参数限制最大滞后阶数。

三、p-value解读与判断标准

p-value是ADF检验里最关键的输出。但很多新手会搞混——p-value小到底代表什么?

记住这个口诀:

  • p-value小(<0.05)→ 拒绝原假设 → 序列平稳
  • p-value大(>0.05)→ 不能拒绝原假设 → 序列非平稳

为什么会这样?因为原假设是“有单位根(非平稳)”。p-value小,说明在原假设下出现当前结果的概率极低,所以原假设不成立,序列就是平稳的。

我在项目中遇到过不少同学,看到p-value=0.03就慌了,觉得“这么小是不是有问题?”其实恰恰相反,越小越好!

判断标准总结:

p-value范围 结论 操作建议
p < 0.01 在1%水平上显著平稳 非常可靠,直接使用
0.01 ≤ p < 0.05 在5%水平上显著平稳 可以接受,建议做差分验证
0.05 ≤ p < 0.10 在10%水平上边缘显著 谨慎使用,可能需要差分
p ≥ 0.10 不显著,非平稳 必须做差分或变换

避坑指南:我曾经在做一个国债收益率分析时,发现p-value刚好是0.049,差一点就过了0.05的线。但我没多想就直接用了,结果模型回测一塌糊涂。后来仔细检查,发现数据里有一个异常值把检验结果“拉偏”了。所以我的建议是:p-value在0.05附近时,一定要结合图形和业务逻辑来判断,别只看数字。

四、实战案例:对股票收益率做ADF检验

刚才我们检验了股票价格,结果是非平稳的。那股票收益率呢?理论上收益率应该是平稳的。咱们来验证一下。

# 计算日收益率
returns = price.pct_change().dropna()

# 对收益率做ADF检验
result_ret = adfuller(returns, autolag='AIC')

print(f'收益率ADF统计量: {result_ret[0]:.4f}')
print(f'收益率p-value: {result_ret[1]:.6f}')
print('临界值:')
for key, value in result_ret[4].items():
    print(f'  {key}: {value:.4f}')

输出结果:

收益率ADF统计量: -15.2345
收益率p-value: 0.000000
临界值:
  1%: -3.4369
  5%: -2.8643
  10%: -2.5683

看到没?p-value几乎为0,ADF统计量-15.23远小于1%临界值-3.44。这说明收益率序列是高度平稳的。这也符合金融理论——收益率通常围绕均值波动,没有长期趋势。

你想想看,如果收益率都不平稳,那股票市场就乱套了——意味着你可以用历史收益率预测未来收益率,这显然不现实。

五、知识体系总览

为了帮你理清ADF检验的完整逻辑,我画了一张流程图:

ADF检验知识体系 时间序列数据 ADF回归方程 ΔY_t = α + βt + γY_{t-1} + ΣδΔY_{t-p} + ε 原假设H₀: γ=0 (有单位根,非平稳) 备择假设H₁: γ<0 (无单位根,平稳) ADF统计量 + p-value + 临界值 p-value < 0.05 → 拒绝H₀ → 平稳 p-value ≥ 0.05 → 不能拒绝H₀ → 非平稳

这张图把ADF检验的完整流程串起来了:从输入数据,到建立回归方程,再到假设检验,最后根据p-value做出判断。你可以在做分析时把它当作一个检查清单。

六、常见问题与避坑指南

问题1:为什么我的p-value总是很大?

最常见的原因是数据本身确实是非平稳的,比如股票价格、GDP等。另一个可能是你选的滞后阶数不对。试试autolag='AIC',让程序自动选。

问题2:p-value刚好等于0.05怎么办?

我曾经在做一个汇率分析时遇到过这种情况。我的建议是:

  • 换一个显著性水平试试(比如0.01或0.10)
  • 结合图形判断(看ACF/PACF图)
  • 做一阶差分后再检验,看差分后是否显著平稳

问题3:ADF检验和KPSS检验有什么区别?

简单说:ADF的原假设是非平稳,KPSS的原假设是平稳。我个人的习惯是两个都做,交叉验证。如果ADF说平稳、KPSS也说平稳,那基本稳了;如果两个都说非平稳,那肯定不稳;如果结果矛盾,就要小心了。

实用建议:在实际项目中,我通常会用adfuller做初步判断,然后用kpss做二次验证。两个检验都通过,我才放心地说“这个序列是平稳的”。

好了,这一讲的内容就到这里。ADF检验是时间序列分析的基础工具,掌握了它,你就能对数据的平稳性做出量化判断。下一讲我们会聊差分操作——当数据不平稳时,怎么把它变平稳。


公众号:蓝海资料掘金营,微信deep3321