2. 样本切分基础:时间序列切分原则、避免未来信息泄露、训练集/验证集/测试集划分比例
在信贷额度模型中,样本切分不是简单的随机抽样。由于信贷数据天然带有时间顺序,且模型需要预测未来申请人的违约风险,因此必须严格遵循时间序列切分原则。错误的切分方式会导致未来信息泄露,使模型在离线验证时表现优异,上线后却大幅衰退。
2.1 时间序列切分的核心原则
信贷样本切分必须遵守以下三条硬性规则:
- 时间顺序不可逆:训练集的时间窗口必须早于验证集,验证集早于测试集。禁止使用未来数据预测过去。
- 样本点不可交叉:同一个客户在切分周期内只能出现在一个数据集中,避免客户信息在训练集和测试集之间泄漏。
- 保持业务周期完整性:切分时需考虑信贷业务的季节性、政策变更、客群迁移等因素,确保每个子集都包含完整的业务周期。
关键概念: 时间序列切分与随机切分的本质区别在于——随机切分假设样本独立同分布,而信贷数据中不同时间窗口的样本分布(如客群质量、宏观经济环境)可能发生显著变化。
2.2 避免未来信息泄露
未来信息泄露是额度模型中最隐蔽、破坏性最大的错误。它发生在模型在训练时“看到”了本不该看到的信息,导致验证指标虚高。
| 泄露类型 | 典型场景 | 后果 |
|---|---|---|
| 时间穿越 | 用2024年12月的数据预测2024年6月的违约 | 模型学到的是“未来结果”,而非真实规律 |
| 特征泄漏 | 使用“是否已逾期”作为训练特征,但该特征在放款时不可知 | 模型在线上无法获取该特征,效果崩溃 |
| 样本泄漏 | 同一客户在训练集和测试集中同时出现 | 模型“记住”了客户,泛化能力被高估 |
| 标签泄漏 | 使用未来时间窗口的标签(如逾期30天)作为当前样本的标签 | 标签与特征时间错位,模型无法正确学习 |
⚠️ 实战避坑: 在构造特征时,必须确保每个样本的特征只使用该样本时间点之前的信息。例如,计算“过去3个月平均借款金额”时,不能包含样本时间点之后的借款记录。
2.3 训练集/验证集/测试集划分比例
信贷额度模型通常采用时间窗口划分法,而非固定比例。以下是一种经过工业验证的划分方案:
| 数据集 | 时间窗口 | 占比(约) | 用途 |
|---|---|---|---|
| 训练集 | 最早 60% ~ 70% 的时间段 | 60% ~ 70% | 模型参数学习、特征筛选 |
| 验证集 | 训练集之后 15% ~ 20% 的时间段 | 15% ~ 20% | 超参数调优、模型选择、早停 |
| 测试集 | 最后 15% ~ 20% 的时间段 | 15% ~ 20% | 最终模型评估、泛化能力验证 |
划分比例调整原则:
- 如果业务周期较短(如<6个月),可适当增大训练集比例至75%,验证集和测试集各占12.5%。
- 如果数据量极大(如>100万样本),可适当减小训练集比例至60%,但需保证验证集和测试集样本量足够(至少各1万以上)。
- 如果业务存在明显的季节性(如春节、双十一),必须确保每个子集都包含完整的季节性周期。
2.4 时间序列切分流程
以下SVG图展示了从原始数据到最终评估的完整切分流程:
2.5 代码实现:时间序列切分
以下Python代码展示了如何基于时间戳进行严格的时间序列切分:
import pandas as pd
from datetime import datetime
def time_series_split(df, date_col, train_ratio=0.7, val_ratio=0.15):
"""
时间序列样本切分函数
Parameters:
df: DataFrame,包含时间戳列
date_col: 时间戳列名
train_ratio: 训练集比例
val_ratio: 验证集比例
Returns:
train_df, val_df, test_df
"""
# 按时间排序
df = df.sort_values(by=date_col).reset_index(drop=True)
# 计算切分点
n = len(df)
train_end = int(n * train_ratio)
val_end = int(n * (train_ratio + val_ratio))
# 切分
train_df = df.iloc[:train_end].copy()
val_df = df.iloc[train_end:val_end].copy()
test_df = df.iloc[val_end:].copy()
# 验证时间顺序
assert train_df[date_col].max() <= val_df[date_col].min(), "训练集与验证集时间重叠!"
assert val_df[date_col].max() <= test_df[date_col].min(), "验证集与测试集时间重叠!"
return train_df, val_df, test_df
# 使用示例
# train, val, test = time_series_split(data, 'apply_date', 0.7, 0.15)
💡 进阶技巧: 如果数据量较大,建议使用滚动时间窗口进行多轮验证(Time Series Cross-Validation),而不是单一切分。例如:训练集使用[1-6月],验证集使用7月;下一轮训练集使用[1-7月],验证集使用8月,以此类推。
2.6 常见错误与检查清单
| 错误类型 | 检查方法 | 修复方案 |
|---|---|---|
| 训练集与测试集时间重叠 | 打印各数据集的日期范围,确认无交叉 | 重新按时间顺序切分 |
| 特征包含未来信息 | 检查特征计算逻辑,确保只使用历史数据 | 使用滞后特征或时间窗口聚合 |
| 验证集样本量不足 | 统计验证集样本数,确保>5000 | 增大验证集比例或使用交叉验证 |
| 测试集分布偏移 | 对比训练集与测试集的客群分布 | 检查时间窗口是否包含特殊事件 |
总结: 时间序列切分是信贷额度模型的基础保障。严格遵循时间顺序、避免未来信息泄露、合理分配训练/验证/测试集比例,是构建可靠模型的第一步。在实际项目中,建议将切分逻辑封装为可复用的函数,并在每次建模前执行完整性检查。