4. 平稳性检验与差分处理

任务目标

对给定的非平稳时间序列执行ADF(Augmented Dickey-Fuller)检验,量化判断其平稳性;若判定为非平稳,则通过一阶差分(或必要时做对数变换后再差分)使其平稳,并再次用ADF检验验证处理效果,为后续时序建模提供平稳输入。

环境与依赖

本案例使用Python 3.9+,依赖 numpy、pandas、statsmodels(版本≥0.13)。若未安装,执行:

pip install numpy pandas statsmodels

完整实现

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

# ---------- 1. 构造非平稳示例序列(随机游走 + 确定性趋势) ----------
np.random.seed(42)
n = 200
t = np.arange(n)
# 确定性线性趋势 + 随机游走分量 + 噪声
trend = 0.05 * t
random_walk = np.cumsum(np.random.normal(0, 1, n))
noise = np.random.normal(0, 0.5, n)
series = trend + random_walk + noise

# ---------- 2. ADF检验函数(返回统计量与p值) ----------
def adf_test(ts, name):
    result = adfuller(ts, autolag='AIC')
    stat, p_value = result[0], result[1]
    print(f"[{name}] ADF统计量: {stat:.4f}, p值: {p_value:.4f}")
    print(f"  判定: {'平稳' if p_value < 0.05 else '非平稳'} (显著性水平0.05)")
    return p_value

# ---------- 3. 原始序列平稳性检验 ----------
print("=== 步骤1: 原始序列ADF检验 ===")
p_orig = adf_test(series, "原始序列")

# ---------- 4. 若非平稳,执行差分处理 ----------
if p_orig >= 0.05:
    print("\n=== 步骤2: 原始序列非平稳,执行一阶差分 ===")
    diff_series = np.diff(series)
    p_diff = adf_test(diff_series, "一阶差分后序列")
    
    # 若一阶差分后仍非平稳,尝试对数变换后再差分
    if p_diff >= 0.05:
        print("\n=== 步骤3: 一阶差分仍非平稳,尝试 log(series) 后再差分 ===")
        # 确保序列为正(此处原始序列均值为正,偏移保证正值)
        shifted = series - series.min() + 1.0
        log_diff = np.diff(np.log(shifted))
        p_logdiff = adf_test(log_diff, "log差分后序列")
        final_series = log_diff
    else:
        final_series = diff_series
else:
    final_series = series

# ---------- 5. 输出最终结果 ----------
print("\n=== 处理完成 ===")
print(f"最终用于建模的序列长度: {len(final_series)}")
print("平稳性判定标准: ADF检验p值 < 0.05 则拒绝单位根原假设,认为序列平稳。")

运行方式

将上述代码保存为 stationarity_check.py,在终端执行:

python stationarity_check.py

验证方法与通过条件

运行后观察控制台输出,满足以下条件即判定案例通过:

  • 原始序列的ADF检验p值大于等于0.05,输出“非平稳”——这证明构造的示例数据确实需要差分处理;
  • 一阶差分后序列的ADF检验p值小于0.05,输出“平稳”——证明差分操作成功消除了非平稳性;
  • 若一阶差分后p值仍≥0.05(取决于随机种子,本代码设定下通常一阶差分即可平稳),代码会自动尝试log差分并给出对应判定;
  • 最终打印的序列长度与处理方式一致(差分后长度减1,log差分同样减1)。

若需验证其他真实数据集,将 series 替换为实际数据(pandas Series或numpy数组)即可,ADF检验与差分逻辑无需改动。

常见问题

  • ADF检验的滞后阶数如何选择? 代码中 autolag='AIC' 让statsmodels自动按AIC准则选择最优滞后阶数,避免手动调参。
  • 差分后序列长度减少1是否影响建模? 是正常现象。若需与原序列对齐,可在差分前用 shift 操作或建模时调整时间索引。
  • 序列含负值时能否直接取对数? 不能。代码中已通过平移保证序列为正(shifted = series - series.min() + 1.0),实际应用时需根据数据特征选择变换方式(如Box-Cox)。