news 2026/7/14 12:28:38

时间序列平稳性检验:从ADF到KPSS的双重验证策略

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
时间序列平稳性检验:从ADF到KPSS的双重验证策略

1. 时间序列平稳性的核心概念

我第一次接触时间序列分析时,被"平稳性"这个概念折磨得不轻。直到有次分析销售数据,发现预测结果总是离谱,前辈才点醒我:"先检查平稳性!"那什么是平稳性呢?想象你每天记录体重,如果体重始终在70kg上下小幅波动(均值稳定),波动幅度也差不多(方差稳定),今天和昨天的体重关系与上周今天和上周昨天的关系类似(协方差稳定),这就是平稳序列。

严格来说,平稳时间序列需要满足三个条件:

  • 均值稳定:序列的期望值不随时间变化。比如零售店的日销售额没有明显的增长或下降趋势
  • 方差稳定:数据的波动幅度保持恒定。股票价格如果波动越来越大就不满足这个条件
  • 自协方差稳定:相隔相同时间间隔的数据点之间的关系不变。比如月度数据中,今年1月和2月的关系与去年1月和2月的关系应该相似

为什么平稳性这么重要?我吃过亏才明白:大多数时间序列模型(ARIMA等)都假设数据是平稳的。用非平稳数据建模,就像在流沙上盖房子——模型参数会漂移,预测结果根本不可靠。有次我用非平稳的电商流量数据直接建模,预测下周流量会是负值,被同事笑话了好久。

2. ADF检验的实战指南

2.1 ADF检验的原理剖析

ADF检验全称Augmented Dickey-Fuller检验,是检测单位根的经典方法。什么是单位根?可以理解为序列中的"记忆效应"——当前值严重依赖前值,导致冲击的影响永不消退。好比醉酒走路,每一步都受上一步影响,最终轨迹无法预测。

ADF检验的核心是以下回归方程:

Δy_t = α + βt + γy_{t-1} + δ1Δy_{t-1} + ... + δpΔy_{t-p} + ε_t

其中γ就是关键参数:

  • 原假设H0:γ=0(存在单位根,序列非平稳)
  • 备择假设H1:γ<0(不存在单位根,序列平稳)

检验统计量是γ的估计值除以其标准误。这个值越负,越倾向于拒绝原假设。我在金融数据分析时常用三个置信水平:1%、5%、10%,对应不同的临界值。

2.2 Python实现步骤

实际应用中,我推荐使用Python的statsmodels库。以下是完整代码示例:

import pandas as pd from statsmodels.tsa.stattools import adfuller import matplotlib.pyplot as plt # 读取数据(示例为模拟的销售数据) data = pd.read_csv('sales_data.csv', parse_dates=['date'], index_col='date') # 可视化观察 plt.figure(figsize=(12,6)) plt.plot(data['sales']) plt.title('Daily Sales Trend') plt.grid(True) plt.show() # 执行ADF检验 result = adfuller(data['sales'], autolag='AIC') # 自动选择最佳滞后阶数 print(f'ADF Statistic: {result[0]:.4f}') print(f'p-value: {result[1]:.4f}') print('Critical Values:') for key, value in result[4].items(): print(f' {key}: {value:.4f}') # 结果解读 if result[1] < 0.05: print("拒绝原假设,序列平稳") else: print("无法拒绝原假设,序列非平稳")

几个实用技巧:

  1. 滞后阶数选择:建议用'autolag='AIC''自动确定,比固定阶数更可靠
  2. 趋势项处理:如果数据有明显趋势,添加参数regression='ct'包含常数项和趋势项
  3. 季节性数据:先做季节性差分再用ADF检验

2.3 结果解读的常见误区

新手常犯的错误是只看p值。我有三点经验:

  • 临界值对比:当检验统计量小于1%临界值,可以99%确信序列平稳
  • 结合图形判断:即使ADF显示平稳,如果图形有明显趋势,可能需要差分
  • 样本量影响:小样本容易得出假平稳结论,建议至少50个以上数据点

曾经分析过一组用户活跃数据,ADF的p值是0.06(略高于0.05),但图形显示均值稳定。后来扩大样本量重新检验,确认确实是平稳序列。

3. KPSS检验的深度解析

3.1 与ADF检验的哲学差异

KPSS检验(Kwiatkowski-Phillips-Schmidt-Shin Test)与ADF检验的假设正好相反:

  • 原假设H0:序列是趋势平稳的(或水平平稳)
  • 备择假设H1:序列存在单位根

这种互补性很有意思:ADF说"假设你有病,证明你没病",KPSS说"假设你健康,证明你有病"。就像医生用不同检查手段交叉验证病情。

KPSS检验的统计量构造也不同,它基于残差的累积和:

KPSS = \frac{1}{T^2} \sum_{t=1}^T \frac{S_t^2}{s^2(l)}

其中S_t是部分和,s²(l)是长期方差估计。

3.2 实际应用演示

继续用Python实现KPSS检验:

from statsmodels.tsa.stattools import kpss # 执行KPSS检验 result_kpss = kpss(data['sales'], regression='c') # 'c'表示水平平稳,'ct'表示趋势平稳 print(f'KPSS Statistic: {result_kpss[0]:.4f}') print(f'p-value: {result_kpss[1]:.4f}') print('Critical Values:') for key, value in result_kpss[3].items(): print(f' {key}: {value:.4f}') # 结果解读 if result_kpss[1] < 0.05: print("拒绝原假设,序列非平稳") else: print("无法拒绝原假设,序列平稳")

注意点:

  • regression参数:'c'检验水平平稳,'ct'检验趋势平稳,选错会导致误判
  • 带宽选择:默认使用Andrews带宽,对长期方差估计影响很大
  • 与ADF结合:当两者结论矛盾时,说明可能是趋势平稳或差分平稳

3.3 检验结果冲突怎么办?

我在分析GDP数据时遇到过典型冲突:

  • ADF检验:p=0.12 → 不拒绝非平稳
  • KPSS检验:p=0.03 → 拒绝平稳

这种矛盾其实揭示了趋势平稳性的存在。解决方案是:

  1. 先对数据去趋势(用线性回归拟合趋势线并减去)
  2. 对残差再做ADF检验
  3. 如果此时ADF显示平稳,说明原序列是趋势平稳的

具体操作:

from sklearn.linear_model import LinearRegression import numpy as np # 提取时间趋势项 X = np.arange(len(data)).reshape(-1, 1) y = data['sales'].values model = LinearRegression().fit(X, y) trend = model.predict(X) # 去趋势 detrended = y - trend # 检验去趋势后的序列 result_adf_detrended = adfuller(detrended) print(f'去趋势后ADF p值: {result_adf_detrended[1]:.4f}')

4. 双重检验的综合策略

4.1 四种典型情况分析

根据ADF和KPSS的组合结果,可以得出更精确的判断:

案例ADF结果KPSS结果结论处理方法
1非平稳非平稳真实非平稳需要差分
2平稳平稳严格平稳直接建模
3非平稳平稳趋势平稳去除趋势
4平稳非平稳差分平稳使用差分

最棘手的是案例3和案例4。我总结的决策流程:

  1. 先看ADF:如果拒绝非平稳,进入步骤2;否则直接差分
  2. 看KPSS:如果KPSS也接受平稳,则是严格平稳;如果KPSS拒绝,可能是差分平稳
  3. 对差分后序列重新检验,确认是否转为平稳

4.2 金融时间序列的完整案例

以某股票日收盘价为例,演示完整分析流程:

# 获取股票数据 import yfinance as yf stock = yf.download('AAPL', start='2020-01-01', end='2023-12-31') # 原始序列检验 adf_result = adfuller(stock['Close']) kpss_result = kpss(stock['Close']) print(f"原始序列 - ADF p值: {adf_result[1]:.4f}, KPSS p值: {kpss_result[1]:.4f}") # 情况3处理:尝试去趋势 X = np.arange(len(stock)).reshape(-1, 1) y = stock['Close'].values model = LinearRegression().fit(X, y) stock['Detrended'] = y - model.predict(X) # 检验去趋势后序列 adf_detrended = adfuller(stock['Detrended']) print(f"去趋势后 - ADF p值: {adf_detrended[1]:.4f}") # 情况4处理:尝试一阶差分 stock['Diff'] = stock['Close'].diff().dropna() adf_diff = adfuller(stock['Diff']) kpss_diff = kpss(stock['Diff']) print(f"一阶差分 - ADF p值: {adf_diff[1]:.4f}, KPSS p值: {kpss_diff[1]:.4f}")

实际输出可能显示:

  • 原始序列:ADF p=0.98(非平稳),KPSS p=0.01(非平稳)→ 案例1
  • 一阶差分后:ADF p=0.01(平稳),KPSS p=0.10(平稳)→ 案例2 说明该股票价格是一阶差分平稳的,适合用ARIMA(1,1,1)等模型。

4.3 最佳实践建议

根据我的项目经验,推荐以下工作流:

  1. 可视化先行:绘制序列图、ACF/PACF图,形成初步判断
  2. 双重检验:同时进行ADF和KPSS检验,记录p值和检验统计量
  3. 矛盾解析
    • ADF平稳但KPSS非平稳 → 尝试差分
    • ADF非平稳但KPSS平稳 → 尝试去趋势
  4. 转换验证:对转换后数据重新检验,直到获得一致结论
  5. 模型适配:根据最终平稳类型选择建模方法:
    • 严格平稳:ARMA
    • 趋势平稳:ARIMA+趋势外生变量
    • 差分平稳:ARIMA
    • 仍不平稳:考虑季节性差分或更复杂转换

记住:没有放之四海而皆准的方法。有次分析气象数据,常规方法都无效,最后发现需要用Box-Cox变换处理异方差后才显现平稳性。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/14 12:27:51

Topit深度解析:如何用macOS窗口置顶技术提升3倍工作效率?

Topit深度解析&#xff1a;如何用macOS窗口置顶技术提升3倍工作效率&#xff1f; 【免费下载链接】Topit Pin any window to the top of your screen / 在Mac上将你的任何窗口强制置顶 项目地址: https://gitcode.com/gh_mirrors/to/Topit 你是否曾在多任务工作中频繁切…

作者头像 李华
网站建设 2026/7/14 12:27:31

如何彻底解决PDF字体缺失问题:PDF补丁丁字体嵌入功能完整教程

如何彻底解决PDF字体缺失问题&#xff1a;PDF补丁丁字体嵌入功能完整教程 【免费下载链接】PDFPatcher PDF补丁丁——PDF工具箱&#xff0c;可以编辑书签、剪裁旋转页面、解除限制、提取或合并文档&#xff0c;探查文档结构&#xff0c;提取图片、转成图片等等 项目地址: htt…

作者头像 李华
网站建设 2026/7/14 12:27:25

如何快速上手PilotGo-plugin-redis?5分钟搭建Redis集群监控系统

如何快速上手PilotGo-plugin-redis&#xff1f;5分钟搭建Redis集群监控系统 【免费下载链接】PilotGo-plugin-redis PilotGo redis plugin to maintain and monitor redis cluster. 项目地址: https://gitcode.com/openeuler/PilotGo-plugin-redis 前往项目官网免费下载…

作者头像 李华