当前位置: 首页 > news >正文

你的时间序列真的平稳吗?手把手教你用ADF检验(Dickey-Fuller)和滚动统计为预测模型打好基础

时间序列平稳性诊断实战:从理论到Python实现

时间序列分析中,平稳性检验是建模前的关键步骤。许多经典预测模型(如ARIMA)都建立在数据平稳的假设之上。但现实中的时间序列往往带有趋势或季节性,直接建模会导致预测失效。本文将系统讲解平稳性的核心概念,并手把手演示如何通过ADF检验和滚动统计方法诊断时间序列的平稳性。

1. 平稳性的本质与分类

1.1 严平稳与宽平稳

严平稳要求序列的所有统计特性(包括高阶矩)都不随时间变化。数学上,对任意时间位移τ,联合概率分布满足:

F_{X}(x_{t_1},...,x_{t_k}) = F_{X}(x_{t_1+τ},...,x_{t_k+τ})

宽平稳(弱平稳)则只需满足三个条件:

  1. 均值恒定:E[X_t] = μ(与t无关)
  2. 方差恒定:Var(X_t) = σ²(有限且不变)
  3. 自协方差仅与时滞相关:Cov(X_t, X_s) = γ(|t-s|)

实际分析中通常使用宽平稳标准,因其更易检验且大多数模型只需满足弱平稳条件

1.2 非平稳序列的典型特征

特征类型表现形式对建模的影响
趋势性长期上升/下降导致伪回归问题
季节性周期性波动预测出现系统性偏差
结构突变统计特性突然变化模型参数失效

2. 视觉诊断:滚动统计法

2.1 移动窗口技术实现

import pandas as pd import matplotlib.pyplot as plt def plot_rolling_stats(series, window=12): """绘制滚动统计量""" # 计算滚动统计量 rolling_mean = series.rolling(window=window).mean() rolling_std = series.rolling(window=window).std() # 创建画布 plt.figure(figsize=(12, 6)) # 绘制原始序列 plt.plot(series, color='blue', label='Original') plt.plot(rolling_mean, color='red', label='Rolling Mean') plt.plot(rolling_std, color='black', label='Rolling Std') plt.legend(loc='best') plt.title('Rolling Mean & Standard Deviation') plt.show() # 示例使用 from statsmodels.datasets import co2 data = co2.load().data plot_rolling_stats(data['co2'], window=24)

2.2 解读要点

  • 平稳序列:滚动均值和标准差应在小范围内波动
  • 存在趋势:滚动均值呈现明显上升/下降
  • 方差非恒定:滚动标准差呈现规律性变化

窗口大小的选择:对于月度数据,通常选择12或24;季度数据选择4。窗口过大会平滑过多细节,过小则波动剧烈难以判断

3. 统计检验:ADF测试详解

3.1 ADF检验的数学模型

ADF检验通过以下回归模型进行:

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

其中关键假设检验为:

  • H₀: γ = 0 (存在单位根,序列非平稳)
  • H₁: γ < 0 (序列平稳)

3.2 Python实现与结果解读

from statsmodels.tsa.stattools import adfuller def adf_test(series, regression='c'): """执行ADF检验并格式化输出""" result = adfuller(series, regression=regression) print('ADF Statistic: %f' % result[0]) print('p-value: %f' % result[1]) print('Critical Values:') for key, value in result[4].items(): print('\t%s: %.3f' % (key, value)) if result[1] > 0.05: print("未能拒绝原假设 - 序列可能非平稳") else: print("拒绝原假设 - 序列可能是平稳的") # 检验CO2数据 adf_test(data['co2'].dropna())

典型输出结果解析:

ADF Statistic: -2.312 p-value: 0.167 Critical Values: 1%: -3.440 5%: -2.866 10%: -2.569

判断规则:

  1. ADF统计量<临界值(绝对值比较)→ 拒绝H₀
  2. p-value< 0.05 → 拒绝H₀

3.3 检验类型选择

回归类型模型包含项适用场景
'c'常数项无趋势序列
'ct'常数+趋势项有趋势序列
'nc'无附加项罕见,理论分析

4. 非平稳序列的转换方法

4.1 差分处理

一阶差分公式:

diff_1 = series.diff().dropna()

季节性差分(以12个月为例):

diff_seasonal = series.diff(12).dropna()

4.2 对数转换

适用于指数增长趋势:

log_series = np.log(series)

4.3 组合策略

# 先对数再差分 transformed = np.log(series).diff().dropna()

转换效果评估矩阵:

方法适用场景优点缺点
一阶差分线性趋势简单直接可能过度差分
季节性差分周期性波动消除季节影响需要知道周期长度
对数变换指数趋势稳定方差对零值敏感

5. 进阶诊断:KPSS与PP检验

5.1 KPSS检验

与ADF检验互为补充:

from statsmodels.tsa.stattools import kpss def kpss_test(series, regression='c'): result = kpss(series, regression=regression) print('KPSS Statistic: %f' % result[0]) print('p-value: %f' % result[1]) print('Critical Values:') for key, value in result[3].items(): print('\t%s: %.3f' % (key, value))

5.2 组合判断策略

ADF结果KPSS结果结论
拒绝H₀不拒绝H₀确定平稳
不拒绝H₀拒绝H₀确定非平稳
都拒绝H₀都拒绝H₀需进一步分析

6. 实战案例:股票价格序列分析

以苹果公司股价为例:

import yfinance as yf # 获取数据 aapl = yf.download('AAPL', start='2020-01-01', end='2023-01-01')['Adj Close'] # 可视化分析 plot_rolling_stats(aapl, window=30) # ADF检验 adf_test(aapl, regression='ct') # 转换后检验 log_returns = np.log(aapl).diff().dropna() adf_test(log_returns)

关键发现:

  • 原始股价序列ADF检验p值为0.98,强烈非平稳
  • 对数收益率序列p值<0.01,可视为平稳

7. 建模前的完整性检查清单

  1. 视觉检查:绘制原始序列和滚动统计量
  2. ADF检验:选择适当的回归类型
  3. 转换验证:每次转换后重新检验
  4. 残差诊断:建模后检查残差是否白噪声
def full_diagnostic(series): """完整诊断流程""" # 1. 绘制原始序列 plt.figure(figsize=(12,4)) plt.subplot(121) series.plot(title='Original Series') # 2. 绘制滚动统计 plt.subplot(122) plot_rolling_stats(series) # 3. 执行ADF检验 print("\nADF Test Results:") adf_test(series) # 4. 执行KPSS检验 print("\nKPSS Test Results:") kpss_test(series)

在真实项目中,我发现同时使用多种检验方法可以避免单一方法的局限性。特别是对于金融时间序列,结合ADF和KPSS检验能给出更可靠的结论。当检验结果出现矛盾时,建议优先考虑ADF结果,并辅以视觉分析。

http://www.jsqmd.com/news/794219/

相关文章:

  • 使用Taotoken CLI工具一键配置多开发环境接入信息
  • 国内主流AI开发框架横向性能评测
  • react native(学习笔记第四课) 英语打卡微应用(3)-ocr的文字转化成语音文件(tts)
  • esp32开发与应用(wifi和蓝牙开发)
  • SPINNERchip:3G基带协处理器的异构计算与低功耗设计
  • UCC25600 LLC谐振变换器:从补偿网络设计到软启动与过流保护的实战调试
  • Java中的形式化方法
  • ARM虚拟定时器CNTV_TVAL寄存器详解与应用
  • 一文吃透Python全体系,从入门到精通,全程干货无废话
  • SITS2026隐藏资源全解锁,如何通过“非公开日程”接触OpenAI、DeepMind及中国大模型核心团队?
  • TrollInstallerX终极指南:3分钟搞定iOS 14-16.6.1越狱安装的完整教程
  • Qt界面嵌入Halcon窗口实战:告别独立弹窗,实现一体化图像处理界面
  • SpireMS的std_msgs消息详解
  • Sketchfab模型下载终极指南:3步免费获取离线3D模型
  • Prometheus监控主机,Grafana成图
  • arduino-跑马灯
  • 在自动化脚本中如何在自己的后端服务中调用open api进行用户相关操作?
  • 【限时解密】SITS 2026最新《AI原生应用SLA分级白皮书》核心框架(V2.3.1版,仅开放72小时)
  • 【2024最后窗口期】SITS2026合规测试套件已冻结封版——你的AI研发管线还卡在人工回归阶段?
  • 别再只会看P值了!用Python的Seaborn和Statsmodels画QQ图,5分钟诊断你的数据正态性
  • 别盲目跟风!程序员转大模型,先搞懂这6个行业真相
  • 别再死记公式了!用Python+ROS从零推导差速机器人运动模型(附代码)
  • ARM架构SPSR寄存器与异常处理机制详解
  • LDO线性稳压器原理与应用设计指南
  • DCS-Control拓扑在汽车电源管理中的频率优化与EMI设计
  • LangGraph 多 Agent 架构与 Supervisor 模式
  • ACS运动控制器XSEG功能深度解析:如何用LINE和ARC1/ARC2玩转复杂轨迹规划?
  • 保姆级教程:给Slurm 20.02.3集群添加GTX1080Ti GPU节点(含防火墙和SELinux配置)
  • 基于Laravel与Livewire构建自托管短链接服务:从生成、追踪到部署
  • 免费解锁B站4K大会员视频:Python开源下载工具完全指南