3. 训练集切分概念:时间序列切分、随机切分、分层切分的定义与适用场景
在额度定价模型中,训练集的切分方式直接影响模型对未来样本的泛化能力与业务稳定性。不同的切分策略对应不同的数据依赖假设,错误的选择会导致时序穿越、样本偏差或定价失效。本节系统阐述三种核心切分方法的定义、数学逻辑与适用场景。
3.1 时间序列切分(Time Series Split)
定义:严格按照时间顺序,以某个时间点或时间窗口为界,将历史数据划分为训练集(过去)与测试集(未来)。切分后训练集的时间范围必须完全早于测试集,不允许任何未来信息泄露到训练过程中。
数学逻辑:设数据集按时间戳 t 排序,选择切分点 T,则:
训练集:{ (x_i, y_i) | t_i <= T }
测试集:{ (x_j, y_j) | t_j > T }
适用场景:
- 信贷额度定价模型(如信用卡额度、消费贷利率)
- 宏观经济周期敏感的评分卡
- 在线学习或增量更新场景
- 任何需要验证模型在“未来”表现的风控系统
关键提示:时间序列切分是额度定价的“黄金标准”。因为定价策略必须基于历史数据预测未来违约与收入,任何随机切分都可能引入未来信息,导致模型在线上表现严重高估。
工程建议:在金融风控中,通常按“月份”或“季度”作为切分粒度。例如使用 2023年1月-2024年6月 作为训练集,2024年7月-2024年9月 作为测试集。避免使用“日”级切分,防止节假日或短期波动造成样本不均衡。
3.2 随机切分(Random Split)
定义:不考虑时间顺序,从全量数据中随机抽取一定比例样本作为训练集,剩余作为测试集。通常采用无放回抽样,保证每个样本被选中的概率相等。
数学逻辑:设总样本数为 N,训练集比例 p,则:
训练集:随机抽取 N × p 个样本
测试集:剩余 N × (1-p) 个样本
适用场景:
- 非时序的静态特征建模(如客户画像、产品推荐)
- 模型初期的快速原型验证
- 特征选择与超参数调优的交叉验证
- 数据量极大且时间效应可忽略的场景
风险提示:在额度定价中,随机切分是危险操作。如果数据包含时间趋势(如利率上升期、逾期率季节性波动),随机切分会使训练集和测试集混合不同时期的样本,导致模型学到的是“跨时间平均效应”,而非真实的时序因果关系。线上部署时,模型面对的是未来数据,性能会大幅下降。
3.3 分层切分(Stratified Split)
定义:在保持目标变量(如违约标签、额度等级)分布比例与原始数据集一致的前提下,进行训练集/测试集划分。分层切分可以基于单个标签,也可以基于多个关键特征组合。
数学逻辑:设目标变量 y 有 K 个类别,每类占比 π_k。分层切分保证:
训练集中 y=k 的比例 ≈ π_k
测试集中 y=k 的比例 ≈ π_k
适用场景:
- 样本不平衡的违约预测(如坏账率仅 2%)
- 多等级额度定价(如 A/B/C/D 四档额度)
- 需要保持业务分布一致性的模型验证
- 与时间序列切分结合使用(先分层,再按时间排序)
最佳实践:在额度定价中,推荐“时间序列 + 分层”的混合切分策略。即:先按时间切分保证时序正确性,再在训练集内部按违约标签或额度等级进行分层抽样,确保每个时间窗口内的样本分布与业务实际一致。
3.4 三种切分方法对比
| 对比维度 | 时间序列切分 | 随机切分 | 分层切分 |
|---|---|---|---|
| 核心假设 | 数据存在时间依赖 | 样本独立同分布 | 目标分布需保持稳定 |
| 时序穿越风险 | 无 | 高 | 取决于是否结合时间 |
| 样本分布保真度 | 低(时间窗口可能偏移) | 中等 | 高 |
| 适用数据量 | 任意 | 大样本更稳定 | 小样本也有效 |
| 额度定价推荐度 | ★★★★★ | ★☆☆☆☆ | ★★★★☆(需结合时间) |
| 典型应用 | 额度模型、评分卡 | 快速原型、特征筛选 | 不平衡分类、多等级定价 |
3.5 额度定价中的切分策略选择
在额度定价模型的实际开发中,三种切分方法并非互斥,而是可以组合使用。以下为推荐策略:
- 主策略:时间序列切分 — 保证模型评估的是“预测未来”的能力,避免时序穿越。
- 辅助策略:分层切分 — 在训练集内部按违约标签或额度等级分层,确保模型对少数类样本有足够的拟合能力。
- 验证策略:时间序列交叉验证 — 使用滚动时间窗口(如 expanding window 或 sliding window)进行多轮验证,评估模型在不同时间段的稳定性。
- 避免策略:纯随机切分 — 除非数据量极大且时间效应已被严格证明可忽略,否则不应在额度定价中使用。
代码示例:使用 Python 实现时间序列 + 分层混合切分
import pandas as pd
from sklearn.model_selection import train_test_split
# 假设 df 包含 'date' 和 'default_flag' 列
df = df.sort_values('date')
# 时间切分:按日期分界
train_df = df[df['date'] <= '2024-06-30']
test_df = df[df['date'] > '2024-06-30']
# 分层切分:在训练集内保持违约比例
train_df, val_df = train_test_split(
train_df,
test_size=0.2,
stratify=train_df['default_flag'],
random_state=42
)