本节摘要:去趋势是把估计出的趋势"减掉",差分则是让序列逐项相减。两者都能让非平稳序列变得平稳,是 ARIMA 等下游方法的前提。本节给出"先减后差"还是"先差后减"的工程取舍,并演示 ADF 检验如何确认序列已经平稳。
阅读完本节,你应当能够:
df.shift(1) 与 df.diff(1) 的关系,并解释 lag-k 差分的几何含义。本节把 3.2 估计出的趋势"剥掉"——但用差分而不是减法,给 ARIMA 等下游方法铺路。读完后你掌握"ADF 检验帮选差分阶数"的工程流程。
ARIMA、Prophet 等很多下游方法对输入有一个隐含假设:序列是平稳的(均值和方差随时间不变)。带趋势的序列显然不平稳——均值随时间漂移。如果不平稳化,模型的"拟合优度"会被趋势主导,看不出真正的预测能力。
平稳化是"为下游方法铺路"。两条主流路径:
T(t),然后计算 y'(t) = y(t) - T(t)。结果序列不再有趋势,但仍可能带季节性。Δy(t) = y(t) - y(t-1),不去估计趋势,靠"逐项相减"消除任何非平稳结构。💡 关键直觉:差分不需要先估计趋势——它对所有非平稳(趋势、周期、漂移)一视同仁。这是为什么 ARIMA 的 d 阶差分被广泛使用:它不需要事先知道趋势是什么形态。
import pandas as pd import numpy as np # 一阶差分:y(t) - y(t-1) df = pd.DataFrame({"y": [10, 12, 13, 16, 20, 18, 22, 25]}) df["diff1"] = df["y"].diff(1) # 一阶差分 df["diff2"] = df["y"].diff(1).diff(1) # 二阶差分(在 diff1 上再做一阶) print(df)
直观理解:
y = a + bt 差分后变常数 b。y = a + bt + ct² 差分两次后变常数 2c。y(t) - y(t-m)(m 是周期长度)消除固定周期模式。# 季节差分(m=7:周季节性) df["diff7"] = df["y"].diff(7)
一个常见困惑:先估计趋势、减掉、再做差,还是先做差、再估计趋势?
| 顺序 | 优点 | 缺点 |
|---|---|---|
| 先减后差 | 解释清晰,趋势项被显式分离 | 趋势估计误差会进入差分结果 |
| 先差后减 | 一步到位,模型更稳 | 差分后序列难解释 |
工程上更推荐先差后减:
# 推荐写法:先用一阶差分让序列平稳,再估计剩余趋势 y_diff = s.diff(1).dropna() # 此时 y_diff 的趋势被消除,可以做 ARIMA 拟合 from statsmodels.tsa.arima.model import ARIMA model = ARIMA(s, order=(1, 1, 1)).fit()
⚠️ 常见坑:过度差分。二阶差分在原本已经平稳的序列上做会引入虚假自相关(差分运算本身就是一种滤波器)。一个经验法则:差分后如果方差比原序列更大,往往是过度差分;回到上一阶差分。
差分几次才够?最稳的办法是 ADF 检验(Augmented Dickey-Fuller Test):
from statsmodels.tsa.stattools import adfuller def adf_report(y, name="原序列"): stat, p, *_ = adfuller(y, autolag="AIC") print(f"{name}: ADF stat = {stat:.3f}, p = {p:.4f}", "→", "平稳" if p < 0.05 else "非平稳") adf_report(s, "原序列(含趋势)") adf_report(s.diff(1).dropna(), "一阶差分后") adf_report(s.diff(1).diff(1).dropna(), "二阶差分后") # 经验:通常一阶差分就够;过多阶差分会破坏信息
对于带强季节性的序列(如月度数据有 12 个月周期),普通差分可能不够。季节差分 y(t) - y(t-12) 在月度数据上常常能让序列平稳化。但要注意:
y(t) - y(t-1) - y(t-12) + y(t-13)。(D=1, m=12) 的来源。差分后的预测需要"还原"为原尺度:
# ARIMA(1,1,1) 模型 model = ARIMA(s, order=(1, 1, 1)).fit() forecast = model.forecast(steps=12) # forecast 自动还原差分,给出原尺度预测
statsmodels 的 forecast / get_forecast 会自动还原差分;如果你用底层实现手动算,记得把差分结果 cumsum 回去再加回最后一个观测值。
y(t) - y(t-m),常用于月度或季度数据;可以和普通差分叠加使用。