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)。