第一次跑通预测脚本时,看见一条曲线已经很有成就感。但当结果只来自最后一个窗口,它回答的是一次具体预测表现怎样,还没有展示同一方法在不同时间段的变化。
2026 年 5 月,我把 TimesFM 的 ETTh1 快速实验从单窗口扩展为 rolling backtest。本文记下这次改造的设计和当时的结果。
把评估单位从一次预测改成一组窗口
原脚本评估最后一个 96 小时窗口。修改后选择了 8 个非重叠窗口,每个窗口输出 96 个小时的预测。
这样一来,除了一个汇总分数,还可以逐窗口检查:哪些时间段误差较大,某个模型的优势是否只来自其中一段,以及示例图是否碰巧挑中了最好看的窗口。
历史上下文 → 窗口 1:预测 96h → 计算指标
历史上下文 → 窗口 2:预测 96h → 计算指标
…
历史上下文 → 窗口 8:预测 96h → 计算指标
↓
保留逐窗口结果与汇总结果
窗口设计只是评估的一部分。复现实验时,还需要一并核对数据划分、输入上下文、预处理和模型版本;这些信息决定了数字能否相互比较。
给模型放上简单的对照
实验保留了 SeasonalNaive_24h,又加入 SeasonalNaive_168h,分别用一天和一周的季节性作为简单对照。
简单方法有一个好处:它给复杂模型的结果提供了可解释的参照。如果只报告基础模型自己的误差,很难判断这个数值在当前数据上意味着什么。
当时记录的结果
| 方法 | MAE | RMSE |
|---|---|---|
| SeasonalNaive_24h | 1.906902 | 2.492032 |
| SeasonalNaive_168h | 1.852737 | 2.473503 |
| TimesFM_2.5_200M | 1.252056 | 1.757624 |
TimesFM 的 P10–P90 区间覆盖率记录为 0.805990。在这组窗口和当时的设置下,TimesFM 的汇总误差低于两个基线;这组结果的范围就是该次 ETTh1 实验。
让结果可以被重新检查
脚本保留了几种互补的输出:
| 文件 | 用途 |
|---|---|
metrics.csv |
三个模型的汇总指标 |
per_window_metrics.csv |
8 个窗口 × 3 个模型的明细 |
forecast_values.csv |
8 × 96 = 768 行逐小时预测 |
timesfm_forecast.png |
最后一个窗口的可视化 |
汇总表适合快速比较,明细表适合解释波动,逐小时值允许重算指标。图片只是其中一种查看方式。
跑通过程中的两个小问题
当时环境里的 NumPy 没有可用的 np.trapz,代码改为使用 np.trapezoid 或梯形积分 fallback;Matplotlib 缓存目录则通过 MPLCONFIGDIR 显式指定,避免环境权限干扰绘图。
这类问题也应该写进运行说明。它们不会改变预测任务本身,却会影响另一个人能否顺利复跑。
下一步更值得看什么
继续实验时,我更想看逐窗口差异,而不仅是再获得一个汇总数字:误差集中在哪段时间,预测区间是否稳定,不同季节性对照在哪些窗口有竞争力。
相关代码保存在 我的 TimesFM 实验仓库。模型来自 Google Research 的 TimesFM;这里记录的是使用与评估实验。
记于 2026-11-05 · 2026-11-05 更新