4、样本切分原则:避免未来信息泄露、训练集/验证集/测试集的时间顺序划分、滑动窗口与扩展窗口
在信用额度定价模型中,时间序列数据的样本切分与独立同分布(i.i.d.)数据有本质区别。错误的切分方式会导致未来信息泄露,使模型在离线验证时表现优异,上线后却大幅衰退。本章围绕时序样本切分的三大核心原则展开:避免未来信息泄露、时间顺序划分、滑动窗口与扩展窗口。
4.1 未来信息泄露:时序建模的头号风险
未来信息泄露是指模型在训练时接触到了“未来”的真实标签或特征,导致验证指标失真。在信用额度定价中,常见泄露场景包括:
- 全局归一化:使用全量数据的均值/标准差对特征做标准化,相当于用未来数据调整过去样本。
- 标签穿越:将未来逾期标签直接关联到当前时间点的特征上,而未做时间对齐。
- 特征混用:使用未来时间点的宏观指标(如下月CPI)作为当前样本的输入特征。
⚠️ 风险提示: 未来信息泄露在离线AUC上可能带来0.05~0.10的虚高提升,但上线后实际KS往往下降30%以上。这是时序建模中最隐蔽、破坏性最大的错误之一。
4.2 时间顺序划分:训练集 → 验证集 → 测试集
时序样本必须严格按照时间先后顺序进行划分,禁止随机打乱。标准划分策略如下:
| 数据集 | 时间范围 | 用途 | 占比参考 |
|---|---|---|---|
| 训练集 | 最早(如 T₀ ~ T₃) | 模型参数学习 | 60% ~ 70% |
| 验证集 | 中间(如 T₃ ~ T₄) | 超参数调优、早停 | 15% ~ 20% |
| 测试集 | 最晚(如 T₄ ~ T₅) | 最终性能评估 | 15% ~ 20% |
划分时需注意:
- 验证集必须位于训练集之后,测试集位于验证集之后。
- 禁止使用未来数据做交叉验证(如K-Fold),应使用时间序列交叉验证。
- 每个数据集内部保持时间连续性,不跳跃、不混排。
💡 实践建议: 在信用额度定价项目中,建议以“月”为最小时间单位进行切分。例如:训练集使用2023年1~6月,验证集使用2023年7~8月,测试集使用2023年9~10月。
4.3 滑动窗口与扩展窗口:两种主流时序切分策略
当需要多次验证模型在时间轴上的稳定性时,滑动窗口和扩展窗口是两种标准方法。下图展示了二者的核心差异:
4.4 两种窗口策略的对比与选择
| 对比维度 | 滑动窗口 | 扩展窗口 |
|---|---|---|
| 窗口大小 | 固定(如3个月) | 递增(从3个月到12个月) |
| 训练数据量 | 每轮相同 | 每轮递增 |
| 对概念漂移的敏感度 | 高(仅用近期数据) | 低(包含历史数据) |
| 计算开销 | 较低 | 较高(数据量持续增长) |
| 适用场景 | 快速迭代、短期预测 | 长期趋势建模、稳定性评估 |
📌 关键决策: 在信用额度定价中,如果业务策略频繁调整(如每季度更新额度模型),推荐使用滑动窗口;如果希望模型学习长期信用行为规律,且数据量充足,推荐使用扩展窗口。实践中常将两者结合:用扩展窗口训练最终模型,用滑动窗口做回测验证。
4.5 时序切分代码示例(Python)
以下代码展示了如何使用 TimeSeriesSplit 实现滑动窗口与扩展窗口切分:
import numpy as np
from sklearn.model_selection import TimeSeriesSplit
# 模拟时间序列数据(共24个月)
n_months = 24
X = np.random.randn(n_months, 5)
y = np.random.randint(0, 2, n_months)
# 滑动窗口:固定训练集大小为12个月,验证集3个月,测试集3个月
tscv_sliding = TimeSeriesSplit(
n_splits=3,
max_train_size=12, # 固定窗口大小
test_size=3
)
print("=== 滑动窗口切分 ===")
for i, (train_idx, test_idx) in enumerate(tscv_sliding.split(X)):
print(f"Fold {i+1}: 训练集 {train_idx[0]}-{train_idx[-1]}, 测试集 {test_idx[0]}-{test_idx[-1]}")
# 扩展窗口:不限制训练集大小,逐步扩展
tscv_expanding = TimeSeriesSplit(
n_splits=3,
max_train_size=None, # 不限制,逐步扩展
test_size=3
)
print("\n=== 扩展窗口切分 ===")
for i, (train_idx, test_idx) in enumerate(tscv_expanding.split(X)):
print(f"Fold {i+1}: 训练集 {train_idx[0]}-{train_idx[-1]}, 测试集 {test_idx[0]}-{test_idx[-1]}")
4.6 实践检查清单
在信用额度定价项目中,每次进行样本切分前,请逐项确认:
- 时间顺序:训练集、验证集、测试集是否严格按时间先后排列?
- 无未来信息:特征工程中是否使用了未来时间点的数据(如未来宏观指标)?
- 窗口策略:是否根据业务迭代频率选择了合适的窗口类型?
- 验证集独立性:验证集是否完全独立于训练集,且位于训练集之后?
- 测试集隔离:测试集是否仅在最终评估时使用,从未参与训练或调参?
💡 进阶技巧: 对于信用额度定价模型,建议在滑动窗口或扩展窗口的基础上,额外保留一个“冷启动”测试集(如最新3个月数据),专门用于评估模型在最新市场环境下的表现。这有助于提前发现概念漂移。