ARIMA 预测下一个值的方式就是「回归到自己的历史」——用过去几个观测(AR)加上过去几次预测误差(MA)线性组合。中间那个 I(差分)是关键:它先把数据从「累计量」变成「增量」,正如你用 Prometheus 的 rate() 把一路上涨的 counter 转成每秒增量——counter 一直涨没法直接建模,差分之后才平稳可预测。
很多真实序列带趋势(一路涨),但几乎所有经典统计模型都要求序列是「平稳的」——均值、方差不随时间漂移。为什么非平稳不行?因为模型是在「整段历史」上估一组固定参数,若均值一直在变,这组参数就是在拟合一个根本不存在的「平均态」,外推必然失真。ARIMA(p,d,q) 三个旋钮各管一件事:
y_t = c + φ₁y_{t-1} + … + φ_p y_{t-p},φ 就是「每段历史值多大权重」;y'_t = y_t − y_{t-1} 把带趋势的非平稳序列,变成围绕固定均值波动的平稳序列;直觉:先用差分把数据「拉平」,再用「历史值 + 历史误差」做一个线性外推。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% 区间,量化不确定性
指数平滑就是 EWMA(指数加权移动平均)——你在后端到处见过它:TCP 的 RTT 估计、负载均衡的滑动平均、Prometheus 的 irate。一句话:新估计 = α×新观测 + (1−α)×旧估计,越久远的数据权重指数衰减。卡尔曼滤波是它的升级版:额外维护「我对当前估计有多确定」(方差),并据此动态决定该信新观测多一点、还是信旧预测多一点。
真实数据有噪声,你既不能全信最新一个点(抖动),也不能死守旧均值(滞后)。指数平滑用固定 α 折中;Holt-Winters 把它扩展成三条并行的平滑方程,各自用独立系数追踪水平(level)、趋势(trend)、季节(season)三个分量,再叠加成预测。展开公式能看清「指数」二字:
s_t = αy_t + α(1−α)y_{t-1} + α(1−α)²y_{t-2} + …
卡尔曼滤波更进一步,每步分两阶段循环:
卡尔曼增益 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 期
Prophet 把一条时间序列拆成几个独立组件相加:长期趋势 + 年周期 + 周周期 + 节假日效应 + 噪声——就像把一个系统拆成微服务,每个组件单独负责一块、单独可视化、可单独配置。它是 GAM(广义加性模型),不是黑盒——你能看懂每个组件在做什么。
ARIMA 要你懂 p,d,q 怎么调,业务分析师用不来;且对缺失值、异常点、多重季节(周 + 年同时存在)处理麻烦。Prophet(Taylor & Letham 2018)的设计目标就是「analyst-in-the-loop 的规模化预测」——把模型变成几个人能直接理解和手调的旋钮:
每一项都能单独画出来看,也能注入领域先验(比如「这天是大促,量会翻倍」)。两个关键设计值得理解: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) # 分别画出趋势/季节/节假日
把「预测下一个数值」当成「预测下一个 token」——这正是 LLM 干的事。TimesFM(Google 2024)是个 decoder-only transformer,在千亿级真实时间点上预训练,然后对你从没给它见过的新序列直接 zero-shot 预测,不用为这条序列重新训练。类比:从「每个项目自己搭一套预测模型」升级到「调用一个通用的预训练基础设施」。
ARIMA / Prophet 每条序列都要单独 fit,且抓不到复杂的非线性长程依赖;而以往的深度时序模型要为每个数据集单独训练,门槛高。基础模型路线把 LLM 那一套搬过来:
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)