引言
时间序列预测是「用过去推未来」:销量、流量、温度、股价。与普通回归不同,时序数据有自相关(今天影响明天)、趋势、季节性——需要专门的工具链。本文按「由易到难」推进:先讲平稳性与 ACF/PACF 诊断(所有方法的地基),再给经典统计法(指数平滑/ARIMA)、Facebook Prophet(自动处理趋势/节假日)、LSTM(深度学习),最后对比选型与评估。
前置:/ml-supervised-regression/(回归基础)、/ml-deep-learning-advanced/(LSTM)。评估见 /ml-model-evaluation/。
目录
- 1. 时序数据的三大结构
- 2. 平稳性与 ADF 检验
- 3. 自相关分析:ACF 与 PACF
- 4. 经典平滑法:移动平均与指数平滑
- 5. ARIMA:自回归与差分
- 6. Prophet:自动处理趋势与节假日
- 7. LSTM:深度学习时序
- 8. 时序特征工程与训练切分
- 9. 评估指标与模型对比
- 10. 速查表
- 延伸阅读
1. 时序数据的三大结构
一条时间序列 = 趋势 + 季节 + 残差:
y(t) = 趋势 T(t) + 季节 S(t) + 循环 + 残差 ε(t)
(长期方向)(固定周期) (随机噪声)
三种分解(加性/乘性):
import pandas as pd
from statsmodels.tsa.seasonal import seasonal_decompose
decomp = seasonal_decompose(series, model='additive', period=12)
decomp.trend.plot(); decomp.seasonal.plot(); decomp.resid.plot()
| 结构 | 含义 | 例子 |
|---|---|---|
| 趋势 | 长期上升/下降 | 用户增长 |
| 季节 | 固定周期波动 | 周内/年内 |
| 循环 | 无固定周期波动 | 经济周期 |
| 残差 | 不可解释噪声 | 随机扰动 |
心智:先分解看清「有什么」,再选模型——有强趋势/季节用 Prophet/差分,纯随机噪声就别预测。
2. 平稳性与 ADF 检验
平稳性:统计性质(均值/方差)不随时间变化——ARIMA 要求平稳。
from statsmodels.tsa.stattools import adfuller
adf, p, *_ = adfuller(series)
print(f'ADF p-value: {p}')
# p < 0.05 → 平稳(拒绝非平稳假设)
# p >= 0.05 → 非平稳,需差分
处理非平稳:
| 方法 | 做法 | 例子 |
|---|---|---|
| 一阶差分 | y(t) - y(t-1) | 去线性趋势 |
| 对数变换 | log(y) | 方差随水平变大 |
| 季节性差分 | 减去上一年同季 | 去周期 |
series_diff = series.diff().dropna() # 一阶差分
记忆:ADF 检验先验平稳性,非平稳就差分——ARIMA 的「I」就是差分的阶数 d。
3. 自相关分析:ACF 与 PACF
ACF(自相关函数):序列与其滞后版本的相关性——看出「依赖多远」。
PACF(偏自相关):去掉中间滞后影响后的净相关——帮 ARIMA 定阶。
from statsmodels.graphics.tsaplots import plot_acf, plot_pacf
plot_acf(series_diff) # ACF:拖尾或截尾?
plot_pacf(series_diff) # PACF:定 AR 阶数 p
定阶规则(Box-Jenkins):
| 观察 | AR(p) 阶数 | MA(q) 阶数 |
|---|---|---|
| PACF 在 lag p 后截尾 | p = 截尾处 | — |
| ACF 在 lag q 后截尾 | — | q = 截尾处 |
| 两者都拖尾 | 结合 AIC/BIC 搜索 |
记忆:PACF 截尾定 AR 阶,ACF 截尾定 MA 阶;都拖尾就用信息准则搜(见下节)。
4. 经典平滑法:移动平均与指数平滑
简单指数平滑(SES):越近的观测权重越大:
from statsmodels.tsa.holtwinters import ExponentialSmoothing
# Holt-Winters:趋势 + 季节
model = ExponentialSmoothing(
series, trend='add', seasonal='add', seasonal_periods=12
).fit()
pred = model.forecast(12)
| 方法 | 适合 | 公式思想 |
|---|---|---|
| 移动平均 | 平滑噪声 | 近 k 期平均 |
| SES | 无趋势季节 | ŷ = αy + (1-α)ŷ |
| Holt | 有趋势 | 水平 + 趋势 |
| Holt-Winters | 有趋势+季节 | 水平+趋势+季节 |
指数平滑的优点:简单、稳、无需平稳化——适合「先跑通拿基线」。
记忆:平滑法 = 给「时间远近」分配权重——它常是时序项目的最佳基线。
5. ARIMA:自回归与差分
ARIMA(p, d, q) 三个参数:
p = AR 阶(自回归,用过去值预测)
d = 差分阶(去趋势,见第 2 节)
q = MA 阶(误差移动平均)
from statsmodels.tsa.arima.model import ARIMA
import itertools
# 网格搜索最佳 (p, d, q),用 AIC 最小
best_aic, best_cfg = float('inf'), None
for p, d, q in itertools.product(range(3), range(2), range(3)):
try:
model = ARIMA(series, order=(p, d, q)).fit()
if model.aic < best_aic:
best_aic, best_cfg = model.aic, (p, d, q)
except Exception:
pass
model = ARIMA(series, order=best_cfg).fit()
pred = model.forecast(12)
print('最佳阶数:', best_cfg, 'AIC:', best_aic)
SARIMA 扩展:加季节分量 (P, D, Q, m),处理周期数据。
| 模型 | 适用 |
|---|---|
| ARIMA | 平稳化后的一般序列 |
| SARIMA | 有季节周期 |
| 局限性 | 线性、非平稳要差分、难处理多变量 |
记忆:ARIMA 是「差分的线性自回归」——经典可靠,但对非线性/多变量力不从心。
6. Prophet:自动处理趋势与节假日
Prophet(Meta):把序列分解成趋势 + 季节 + 节假日,自动处理缺失值/异常点:
from prophet import Prophet
import pandas as pd
# 数据格式:ds(日期)+ y(值)
df = pd.DataFrame({'ds': dates, 'y': values})
model = Prophet(
yearly_seasonality=True,
weekly_seasonality=True,
daily_seasonality=False,
changepoint_prior_scale=0.05, # 趋势突变灵敏度
)
# 加节假日(电商大促等)
model.add_country_holidays(country_name='CN')
model.fit(df)
future = model.make_future_dataframe(periods=30) # 未来 30 天
forecast = model.predict(future)
Prophet 优点:
| 特性 | 说明 |
|---|---|
| 自动趋势+季节 | 无需手动平稳化 |
| 节假日 | 内置国家节假日 |
| 鲁棒 | 处理缺失/异常 |
| 可解释 | 组件可视化 |
适用:业务指标(销量/流量)带趋势与节假日——比 ARIMA 好用得多。
记忆:Prophet = 傻瓜式自动分解——趋势、季节、节假日都帮你拆好,先试它。
7. LSTM:深度学习时序
LSTM 处理时序:把「过去窗口」当序列输入,预测未来(用 /ml-deep-learning-advanced/ 的 LSTM 结构):
import torch, torch.nn as nn
import numpy as np
# 构造滑窗样本:用前 W 步预测下一步
def make_windows(series, window=12):
X, y = [], []
for i in range(len(series) - window):
X.append(series[i:i+window])
y.append(series[i+window])
return np.array(X, dtype=np.float32), np.array(y, dtype=np.float32)
X, y = make_windows(values, window=12)
class TimeLSTM(nn.Module):
def __init__(self, window=12, hidden=32):
super().__init__()
self.lstm = nn.LSTM(1, hidden, batch_first=True)
self.fc = nn.Linear(hidden, 1)
def forward(self, x): # x: (B, W, 1)
out, _ = self.lstm(x)
return self.fc(out[:, -1]) # 取最后一步 → 预测
model = TimeLSTM()
# 训练循环同标准流程(归一化、损失 MSE、AdamW)
LSTM 时序要点:
| 要点 | 说明 |
|---|---|
| 归一化 | 输入输出都归一化 |
| 滑窗 | 窗口大小 = 依赖长度 |
| 预测方式 | 递归(喂回预测值)或多步直接 |
| 数据量 | 需足够样本(LSTM 数据饥渴) |
| 对比 | 数据少/线性 → 统计法可能更好 |
记忆:LSTM 强在非线性与长依赖,弱在数据饥渴——样本 <1k 先用统计法。
8. 时序特征工程与训练切分
时序「特征工程」(把日期变特征):
df['year'] = df['ds'].dt.year
df['month'] = df['ds'].dt.month
df['dayofweek'] = df['ds'].dt.dayofweek
df['is_holiday'] = df['ds'].isin(holidays)
df['lag_1'] = df['y'].shift(1) # 过去值
df['rolling_7'] = df['y'].rolling(7).mean() # 滚动均值
训练切分(时序不能随机打乱!):
# 随机切分会数据泄露(未来信息进训练)→ 必须按时间切
train = df[df['ds'] < '2025-01-01']
test = df[df['ds'] >= '2025-01-01']
# 滚动验证(walk-forward):更真实的时序评估
# 不断前移训练窗口预测下一段,累计误差
| 切分方式 | 说明 |
|---|---|
| 固定时间切分 | 简单,一次评估 |
| 滚动/扩展窗 | 模拟真实迭代预测,最稳 |
| 交叉验证(普通) | ❌ 时序禁用! |
铁律:时序数据禁止随机打乱切分——未来的信息绝不能泄漏进训练。
9. 评估指标与模型对比
评估指标:
from sklearn.metrics import mean_absolute_error, mean_squared_error
import numpy as np
mae = mean_absolute_error(y_test, y_pred)
rmse = np.sqrt(mean_squared_error(y_test, y_pred))
# MAPE(百分比误差,业务可读)
mape = np.mean(np.abs((y_test - y_pred) / y_test)) * 100
| 指标 | 特点 |
|---|---|
| MAE | 直观,平均绝对误差 |
| RMSE | 放大离群惩罚 |
| MAPE | 百分比,业务友好(y=0 时失效) |
| MASE | 与朴素基线比(推荐对比) |
模型对比表:
| 方法 | 数据量 | 趋势/季节 | 非线性 | 使用难度 |
|---|---|---|---|---|
| 指数平滑 | 少 | ✅ | ❌ | 低 |
| ARIMA | 中 | 靠差分 | ❌ | 中 |
| Prophet | 中 | ✅ 自动 | 部分 | 低 |
| LSTM | 多 | ✅ | ✅ | 高 |
选型建议:先 Prophet 拿基线 → 不够再 LSTM;线性小数据用 ARIMA。对比用统一指标 + 统一滚动窗口。
10. 速查表
| 需求 | 做法 |
|---|---|
| 先看结构 | seasonal_decompose 分解 |
| 平稳性 | ADF 检验 + 差分 |
| 定阶 | ACF/PACF + AIC 搜索 |
| 快速基线 | 指数平滑 / Prophet |
| 强趋势+节假日 | Prophet |
| 非线性大数据 | LSTM |
| 特征工程 | 日期/滞后/滚动特征 |
| 切分 | 按时间切,禁随机打乱 |
| 评估 | MAE/RMSE/MAPE + 滚动验证 |
| 多步预测 | 递归或直接多输出 |
一句话记忆:先分解看趋势季节,ADF 验平稳、差分去趋势;基线用平滑/Prophet,进阶用 LSTM;时序切分按时间、禁打乱;MAE/RMSE 评估、滚动窗口验证。
延伸阅读
- /ml-deep-learning-advanced/ — LSTM 结构细节
- /ml-supervised-regression/ — 回归评估与特征缩放
- /ml-model-deployment/ — 时序模型的批处理部署
- [[statistics]] — 统计检验基础
- [[database]] — 时序数据存储(TSDB)
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。