AI/ML 详解:时间序列预测

Day 35 · 2026-06-21
面向:有编程经验的非 AI 方向工程师 · 难度 中级

ARIMA 自回归积分滑动平均AutoRegressive Integrated Moving Average

经典统计平稳性
一句话类比

ARIMA 预测下一个值的方式就是「回归到自己的历史」——用过去几个观测(AR)加上过去几次预测误差(MA)线性组合。中间那个 I(差分)是关键:它先把数据从「累计量」变成「增量」,正如你用 Prometheus 的 rate() 把一路上涨的 counter 转成每秒增量——counter 一直涨没法直接建模,差分之后才平稳可预测

它解决什么问题 + 工作机制

很多真实序列带趋势(一路涨),但几乎所有经典统计模型都要求序列是「平稳的」——均值、方差不随时间漂移。为什么非平稳不行?因为模型是在「整段历史」上估一组固定参数,若均值一直在变,这组参数就是在拟合一个根本不存在的「平均态」,外推必然失真。ARIMA(p,d,q) 三个旋钮各管一件事:

  • AR(p):用前 p 个观测的加权和预测当下,y_t = c + φ₁y_{t-1} + … + φ_p y_{t-p},φ 就是「每段历史值多大权重」;
  • I(d):差分 d 次去趋势。一阶差分 y'_t = y_t − y_{t-1} 把带趋势的非平稳序列,变成围绕固定均值波动的平稳序列;
  • MA(q):用前 q 个预测误差修正,吸收随机冲击的滞后影响。

直觉:先用差分把数据「拉平」,再用「历史值 + 历史误差」做一个线性外推。AR 和 MA 的区别在于「记什么」:AR 记的是过去的真实值(趋势惯性),MA 记的是过去的预测偏差(系统对突发冲击的余震还没消化完)。两者互补——光有 AR 抓不住一次性扰动的衰减尾巴,光有 MA 抓不住持续动量。带季节的变体叫 SARIMA(再加一组以季节周期为间隔的 AR/MA/差分参数),能同时建模「日内波动」和「周内波动」这种叠加节律。

代码示例
import pandas as pd
from statsmodels.tsa.arima.model import ARIMA

# series: 一列按时间排好的数值(如每月服务器成本)
series = pd.read_csv("cost.csv", index_col="month", parse_dates=True)["usd"]

# order=(p,d,q): 2 阶自回归 + 1 次差分去趋势 + 2 阶滑动平均
model = ARIMA(series, order=(2, 1, 2))
res = model.fit()

# 向前预测 6 步,并给出置信区间
fc = res.get_forecast(steps=6)
print(fc.predicted_mean)            # 点预测
print(fc.conf_int(alpha=0.05))      # 95% 区间,量化不确定性
常见误区 + 实践场景
"ARIMA 能抓长期复杂模式"——错。它本质是线性 + 短记忆模型,遇到多重季节、节假日、非线性突变就吃力(那是 SARIMA / Prophet 的活)。且 d 选错(过度差分)会引入伪相关。
📌 BigCat 场景:预测个人项目的月度云成本、博客流量这类「弱趋势 + 单变量」序列,ARIMA 十几行就够,别一上来就上深度模型——杀鸡用牛刀,还更难解释。
Takeaway + 思考题
💡 ARIMA = 差分把数据拉平 + 用历史值和历史误差做线性外推。简单、可解释、对小数据稳。
🤔 你监控系统里哪些指标是「累计量(counter)」,哪些是「增量(rate)」?哪一类才适合直接喂进 ARIMA?

指数平滑与卡尔曼滤波Exponential Smoothing & Kalman Filter

递归估计状态空间
一句话类比

指数平滑就是 EWMA(指数加权移动平均)——你在后端到处见过它:TCP 的 RTT 估计、负载均衡的滑动平均、Prometheus 的 irate。一句话:新估计 = α×新观测 + (1−α)×旧估计,越久远的数据权重指数衰减。卡尔曼滤波是它的升级版:额外维护「我对当前估计有多确定」(方差),并据此动态决定该信新观测多一点、还是信旧预测多一点。

它解决什么问题 + 工作机制

真实数据有噪声,你既不能全信最新一个点(抖动),也不能死守旧均值(滞后)。指数平滑用固定 α 折中;Holt-Winters 把它扩展成三条并行的平滑方程,各自用独立系数追踪水平(level)、趋势(trend)、季节(season)三个分量,再叠加成预测。展开公式能看清「指数」二字:

s_t = αy_t + α(1−α)y_{t-1} + α(1−α)²y_{t-2} + …

卡尔曼滤波更进一步,每步分两阶段循环:

卡尔曼滤波:predict → update 循环

① 预测 用模型推下一步状态,不确定性(方差)变大
来了一个新观测 (本身也带噪声)
② 更新 按卡尔曼增益 K 加权融合 预测 vs 观测
K 大→信观测;K 小→信预测(由两边方差自动算出)
回到 ① ,逐点递归

卡尔曼增益 K 本质就是个自适应的「信任度调节器」——和你熟悉的自适应退避、动态 TTL 同构;也像分布式系统里融合多个不可靠副本的读数,按各自可信度(方差)加权。和固定 α 的指数平滑相比,卡尔曼的杀手锏是 K 随时间自调:观测特别干净时它放大 K(快速跟随),观测噪声大时它压低 K(稳住不被带偏)——指数平滑做不到这点,它的 α 一旦定下就僵在那。代价是你得显式写出「状态如何演化」和「观测噪声多大」这两个模型,建模成本更高。

代码示例
from statsmodels.tsa.holtwinters import ExponentialSmoothing

# trend + 季节(周期=12) 的三参数指数平滑(Holt-Winters)
model = ExponentialSmoothing(
    series,
    trend="add",            # 加性趋势
    seasonal="add",         # 加性季节
    seasonal_periods=12,        # 12 个月一个周期
)
res = model.fit()              # 自动学 α 等平滑系数
print(res.forecast(6))         # 向前预测 6 期
常见误区 + 实践场景
"α 越大、跟得越紧就越好"——错。α 大 = 对噪声过敏(方差高),α 小 = 反应迟钝(偏差大)。这就是经典的 bias-variance 权衡,没有万能值,要按数据信噪比调。
📌 BigCat 场景:追踪个人/家庭指标(体重、每日专注时长、孩子作息)时,指数平滑给你一条去噪后的趋势线,比盯着原始抖动数据做决策靠谱得多——别被单日波动带节奏。
Takeaway + 思考题
💡 指数平滑 = 权重指数衰减的记忆;卡尔曼 = 带「不确定性管理」的指数平滑,能自动调信任度。
🤔 卡尔曼的「按方差加权融合多源信号」,和你做分布式读时「按副本健康度选数据源」是不是同一个数学?

Prophet 先知模型Prophet (Facebook / Meta)

加性模型可解释
一句话类比

Prophet 把一条时间序列拆成几个独立组件相加:长期趋势 + 年周期 + 周周期 + 节假日效应 + 噪声——就像把一个系统拆成微服务,每个组件单独负责一块、单独可视化、可单独配置。它是 GAM(广义加性模型),不是黑盒——你能看懂每个组件在做什么。

它解决什么问题 + 工作机制

ARIMA 要你懂 p,d,q 怎么调,业务分析师用不来;且对缺失值、异常点、多重季节(周 + 年同时存在)处理麻烦。Prophet(Taylor & Letham 2018)的设计目标就是「analyst-in-the-loop 的规模化预测」——把模型变成几个人能直接理解和手调的旋钮:

Prophet 加性分解

y(t) = g(t) 趋势 + s(t) 季节 + h(t) 节假日 + ε 噪声

g:分段线性/逻辑趋势,自动检测拐点(changepoint)
s:傅里叶级数拟合的周期成分
h:你显式声明的节假日/事件 (寒暑假、大促)

每一项都能单独画出来看,也能注入领域先验(比如「这天是大促,量会翻倍」)。两个关键设计值得理解:changepoint(趋势拐点)——Prophet 在序列里撒一批候选拐点,用正则化让大多数权重归零、只留真正的转折,这和稀疏建模思路一致,避免趋势过拟合;加性 vs 乘性季节——若季节波动幅度随基数变大(量越大、波峰越高),要切成乘性,否则加性会系统性低估高峰。这正是它在业务团队火起来的原因:不是精度最高,而是易用 + 可解释 + 抗缺失值和异常点

代码示例
from prophet import Prophet
import pandas as pd

# Prophet 约定:两列,ds=日期,y=数值
df = pd.read_csv("traffic.csv")        # 含 ds, y 两列

m = Prophet(yearly_seasonality=True,
            weekly_seasonality=True)
m.add_country_holidays(country_name="CN")  # 注入中国节假日
m.fit(df)

future = m.make_future_dataframe(periods=30)  # 未来 30 天
forecast = m.predict(future)
m.plot_components(forecast)               # 分别画出趋势/季节/节假日
常见误区 + 实践场景
"Prophet 是预测神器,啥都比 ARIMA 强"——错。学界对它「默认就好」有批评:在短序列、无明显季节、需要外生变量复杂交互的场景上未必赢。它的强项是易用 + 可解释,不是精度冠军。诚实地说:它常被当成强基线,而不是终点。
📌 BigCat 场景:预测博客/产品的周/年访问量,把寒暑假、长假作为节假日喂进去,Prophet 几行就给出一张可解释的分解图——一眼看清「涨是趋势还是放假效应」。
Takeaway + 思考题
💡 Prophet = 把时序拆成可解释的加性组件,让「人能看懂、能手调」优先于「机器精度最高」。
🤔 当模型可解释(看得见每个组件)和精度更高(但黑盒)冲突时,你的个人决策场景里更看重哪个?

时序基础模型Time-Series Foundation Models · TimesFM

基础模型零样本
一句话类比

把「预测下一个数值」当成「预测下一个 token」——这正是 LLM 干的事。TimesFM(Google 2024)是个 decoder-only transformer,在千亿级真实时间点上预训练,然后对你从没给它见过的新序列直接 zero-shot 预测,不用为这条序列重新训练。类比:从「每个项目自己搭一套预测模型」升级到「调用一个通用的预训练基础设施」。

它解决什么问题 + 工作机制

ARIMA / Prophet 每条序列都要单独 fit,且抓不到复杂的非线性长程依赖;而以往的深度时序模型要为每个数据集单独训练,门槛高。基础模型路线把 LLM 那一套搬过来:

TimesFM:把数值序列当 token 预测

原始序列 切成不重叠 patch decoder-only Transformer 预测未来 patch

patch:把连续数值切成小段(类比 ViT 切图块),大幅缩短序列长度
因果注意力:只看过去,自回归地往前预测

patching(把连续数值切成不重叠小段,像 ViT 切图块、像把字符合成 token)有两个好处:一是把序列长度压到 1/patch,缓解注意力 O(n²) 的开销;二是让模型在「局部形状(patch 内的小波形)」而非「单点数值」上学习,更接近人看波形图的方式。它还输出分位数预测而非单点,天然给出不确定性区间。论文(arXiv 2310.10688, ICML 2024)报告:在千亿真实时间点上预训练后,zero-shot 表现可以接近为单个数据集专门训练的监督模型——这正是「基础模型」一词的含金量所在。

代码示例
# pip install timesfm —— Google 官方 SDK
# 注意:基础模型库 API 迭代较快,以官方仓库为准
import timesfm

tfm = timesfm.TimesFm(
    hparams=timesfm.TimesFmHparams(horizon_len=24),
    checkpoint=timesfm.TimesFmCheckpoint(
        huggingface_repo_id="google/timesfm-1.0-200m"),
)

# 直接 zero-shot:给历史,要未来,无需为这条序列训练
point_forecast, _ = tfm.forecast(
    inputs=[history_values],   # list,每条是一段历史数值
    freq=[0],                  # 0=高频(日/小时), 1=周/月, 2=低频
)
print(point_forecast)
常见误区 + 实践场景
"有了基础模型,ARIMA / Prophet 就过时了"——错。诚实讲:大模型对短序列、小数据是杀鸡用牛刀,成本和延迟更高,可解释性更差;经典方法在「数据少、要解释、要快」时仍是首选。基础模型赢在「海量异构序列、零样本、懒得调参」。
📌 BigCat 场景:想对几十条不同指标一次性出预测、又不想为每条单独调参时,用 TimesFM 的 zero-shot 当快速基线;若某条序列特别重要,再用 ARIMA / Prophet 精雕。
Takeaway + 思考题
💡 时序基础模型 = 把「预测下一段数值」变成「预测下一个 token」,用预训练换 zero-shot 通用性。
🤔 当一个领域出现「预训练 + zero-shot」的基础模型,原有的专用方法会被淘汰,还是退守到「数据少/要解释」的细分场景?

深入资源Further Reading

深入思考Deep Questions

1. ARIMA 用「差分」、Prophet 用「趋势组件」、Transformer 用「自回归」——三者处理「趋势」的哲学有何根本不同?
三种世界观。ARIMA 把趋势当成需要消除的干扰:先差分拉平成平稳序列,再建模波动——趋势不是被理解的,是被「减掉」的。Prophet 把趋势当成需要显式建模的可解释组件:用分段线性/逻辑函数拟合,并自动找拐点,趋势是一等公民、能单独画出来看。Transformer 不预设任何趋势形式,把趋势、季节、噪声一起塞进数据分布,靠海量预训练让模型自己「见过各种趋势」从而泛化——趋势是被隐式记忆的。对应到工程:第一种是「归一化掉再处理」,第二种是「拆成可观测的子系统」,第三种是「端到端学,不做特征工程」。越往后越省人工、越吃数据、越难解释。
2. 卡尔曼滤波的 predict→update 循环,和你熟悉的哪些分布式/系统模式是同构的?
本质是贝叶斯更新:先验(预测) + 似然(观测) → 后验(更新估计),每来一个数据就递归一次。同构的东西很多:(a) 传感器融合——多个不可靠传感器按方差加权,正是卡尔曼增益在做的事;(b) 自适应退避 / 动态 TTL——根据「最近预测有多准」调整信任新信号还是旧状态;(c) 分布式读的副本选择——按副本健康度/延迟方差加权选数据源,数学骨架相同;(d) 更抽象地,它就是在线学习的雏形:用 O(1) 内存增量更新状态,不重算全部历史。理解卡尔曼增益 K = 「该信新数据多少」这个旋钮,你会在很多系统设计里反复认出它。
3. 时序基础模型 zero-shot 真能取代经典方法吗?什么时候经典方法仍不可替代?
短期内不会全面取代,而是分层共存。基础模型的甜区:序列多、异构、懒得逐条调参、可接受黑盒、有 GPU。经典方法不可替代的场景:(a) 数据极少——几十个点,大模型无从发挥,ARIMA/ETS 反而稳;(b) 要可解释——金融、医疗、需要向人解释「为什么预测涨」,Prophet 的分解图无可替代;(c) 要快/要省——边缘设备、高频在线预测,几行统计模型延迟和成本碾压大模型;(d) 有强领域先验——你确切知道节假日/促销规则,显式注入比让模型猜更可靠。规律和 NLP 一样:基础模型抬高了「通用 baseline」的下限,但细分场景的专用方法依然有护城河
4. 几乎所有经典时序方法都假设「平稳性」。这和分布式系统里假设「负载是平稳的」一样危险吗?当假设破裂会怎样?
同样危险,而且失败方式相似。平稳性假设 = 「未来的统计规律和过去一样」,一旦发生结构性突变(regime change)——疫情、政策、产品爆发、相变——模型会自信地错:它仍按旧分布外推,置信区间还很窄,正如容量规划按历史均值估算,碰上突发流量直接被打穿。应对思路也和系统设计相通:(a) 监控残差/漂移,像监控 SLO 一样监控预测误差,超阈值报警重训;(b) 用能局部适应的模型(卡尔曼、滑动窗口)而非一次性全局拟合;(c) 别只信点预测,看区间,把不确定性当一等公民;(d) 承认有些突变本质不可预测,转而设计「快速察觉 + 快速恢复」而不是「精准预言」。预测的成熟,是知道它何时会失效。