验证时间序列预测时,如何避免未来信息泄漏
按时间划分数据,只用过去的数据学习预处理参数。
本文内容
简明答案
预测验证应使用较早的数据训练,再用之后的数据测试。随机划分可能让模型看到真实预测时尚不可用的信息。
从真正需要预测的时刻出发
假设商店每周日晚上预测接下来七天的需求。评估应模拟这个时刻:下一周的销量以及周日之后才公布的信息都不能作为输入。随机划分会混合较早和较晚的记录,让模型看起来比实际部署时更有用。
明确预测起点、预测跨度,以及每项输入什么时候可用。日历信息可以提前知道,实际气温或之后修订的销售总额则不一定可以。如果应用需要天气信息,应使用当时可获得的天气预报,而不是事后观测值。
明确预测跨度
测试窗口应与目标预测跨度一致。标准化等需要学习参数的转换只能在训练集上拟合。滚动特征只能使用预测当时已知的信息。
from sklearn.model_selection import TimeSeriesSplit
observations = list(range(12))
splitter = TimeSeriesSplit(n_splits=3, test_size=2, gap=1)
for train, test in splitter.split(observations):
print(train.tolist(), test.tolist())按具体位置理解时间划分
上面的小例子包含 12 个有序观测、三个各含两行的评估窗口,以及一行间隔。第一轮用位置 0–4 训练,在 6–7 评估;下一轮是 0–6 与 8–9;最后是 0–8 与 10–11。
间隔代表按任务选择的排除范围,并非防止所有泄漏的万能办法。应结合信息发布延迟或目标窗口重叠情况确定。TimeSeriesSplit 按行计数,两行未必等于两天。解释时间窗口前,先检查时间排序、重复、缺失周期和间距是否一致。
检查时间假设
检查排序、缺失日期和采样间隔。若存在信息延迟或标签重叠,可按需要设置间隔,并保留最后一个独立测试时段。
划分正确,仍可能存在泄漏
缩放、缺失填补和特征选择只能在每轮训练数据上拟合,再将得到的变换用于之后的测试数据。Pipeline 有助于组合这些步骤,但无法修复已经包含未来信息的特征。
预测第 t 天的销量时,移动平均应只用先前观测,例如 shift(1).rolling(7).mean()。居中窗口可能包括未来几天。若一次预测整周,预测起点时连本周前几天的真实销量也不知道,不能把它们作为已知输入来预测后几天。
调参之前先比较简单基线
选择与任务一致的基线,例如最后已知值或上一季节周期的对应值。与候选模型使用相同预测起点和跨度。下方示意计算中,实际值为 100、110、90,预测均为 100,MAE 约为 6.67,单位与目标变量相同。
按预测跨度和时间段检查误差,单个平均值可能掩盖高需求日的表现。接近零时,百分比误差可能不合适。保留不参与选模型的最终时段,并在数据形成条件变化后重新评估。
actual = [100, 110, 90]
predicted = [100, 100, 100]
mae = sum(abs(a - p) for a, p in zip(actual, predicted)) / len(actual)
print(round(mae, 2))检查清单
- 按时间先后划分。
- 在每个训练窗口内拟合预处理。
- 检查预测时特征是否已知。
适用范围
TimeSeriesSplit 按行的位置划分数据。要比较相同时间跨度,请先确认采样间隔均匀。