4. 数据准备
贷后模型的时间外验证与稳定性回测,成败往往不取决于算法,而取决于数据准备是否严谨。很多团队在建模阶段指标漂亮,一到时间外回测就出现大幅衰减,根源通常不是模型本身,而是时间切片错位、观察期与表现期定义混乱、标签未成熟或样本选取有偏。本节围绕这五个要点,给出可落地的工程方法。
一、核心原理:时间维度是贷后验证的第一性约束
贷后模型预测的是"未来某段时间内是否发生违约/逾期"这类事件。因此每条样本天然带有三个时间坐标:观察点(Observation Point)、观察期(Observation Window)、表现期(Performance Window)。观察点是做决策的时刻,观察期用于采集该时刻可见的特征,表现期用于等待标签发生。
时间外验证的本质,是用"过去训练、未来验证"的方式模拟真实上线场景。若随机切分样本,会造成特征穿越和标签泄漏,回测结果虚高。正确做法是按时间轴做前向切片:训练集时间早于验证集,验证集早于测试集,且各集合之间保留足够的标签成熟缓冲带。
二、方法流程:从时间切片到样本落地
- 确定观察点频率:贷后监控常用月度或周度观察点。频率越高,样本越多,但相邻样本特征高度相关,需注意去重与抽样。
- 定义观察期长度:通常取观察点前3、6、12个月,用于计算逾期次数、用信率、还款行为等特征。观察期过长会引入陈旧信息,过短则特征不稳定。
- 定义表现期长度:根据产品账期与风险暴露节奏确定。短期现金贷常用30/60/90天,分期产品常用6/12期。表现期必须覆盖绝大多数违约发生的时间窗。
- 按时间切片划分数据集:训练、验证、测试按时间先后排列,并在边界处留出表现期长度的缓冲,避免标签重叠。
- 样本选取与抽样:确定准入客群、排除规则、好坏样本定义,必要时对多数类做下采样或对少数类做加权。
- 标签成熟度检查:只保留表现期已完整结束的样本,未成熟样本打标为"不确定"并排除。
- 数据清洗:处理缺失、异常、重复、穿越变量,输出建模宽表。
三、案例场景:某消费分期贷后模型的切片设计
假设某消费分期产品账期12期,数据覆盖2022-01至2024-06。团队要构建贷后早期预警模型,预测观察点后90天内是否发生M1+逾期。切片方案如下:
| 数据集 | 观察点区间 | 表现期 | 标签成熟截止 | 用途 |
|---|---|---|---|---|
| 训练集 | 2022-01 ~ 2022-12 | 90天 | 2023-03 | 拟合模型 |
| 验证集 | 2023-01 ~ 2023-06 | 90天 | 2023-09 | 调参、选阈值 |
| 测试集 | 2023-07 ~ 2023-12 | 90天 | 2024-03 | 时间外验证 |
| 监控集 | 2024-01 ~ 2024-03 | 90天 | 2024-06 | 稳定性回测 |
注意训练集与验证集之间、验证集与测试集之间均无表现期重叠,且每个集合的标签成熟截止日均早于数据截止日2024-06,保证标签完整。
四、标签成熟度与数据清洗要点
标签成熟度是贷后建模最容易被忽视的坑。若观察点为2024-05,表现期90天,则标签要到2024-08才成熟。在2024-06的数据快照中,这批样本的标签是"未成熟"的,若强行打标为"好客户",会系统性低估风险。
数据清洗需重点关注以下清单:
- 穿越变量剔除:任何在观察点之后产生的字段,如"未来最大逾期天数""结清日期"等,必须排除。
- 缺失值处理:区分"真缺失"与"业务无此环节",前者可填充,后者应单独编码。
- 异常值处理:对金额、比率类字段做分位数截断,避免极端值主导训练。
- 重复样本去重:同一客户同一观察点只保留一条,防止样本权重失衡。
- 标签一致性校验:核对逾期天数口径、M1/M2定义、核销与展期处理规则。
- 时间字段格式统一:全部转为标准日期类型,避免字符串比较导致切片错误。
下面是一段标签成熟度检查与切片生成的伪代码示例:
# 假设 df 含 customer_id, obs_date, perf_days, dpd_max, snapshot_date
df['perf_end'] = df['obs_date'] + pd.to_timedelta(df['perf_days'], unit='D')
df['mature'] = df['perf_end'] <= df['snapshot_date']
# 仅保留成熟样本
df_mature = df[df['mature']].copy()
# 定义标签:表现期内最大逾期天数 >= 30 为坏
df_mature['label'] = (df_mature['dpd_max'] >= 30).astype(int)
# 按观察点时间切片
train = df_mature[df_mature['obs_date'] < '2023-01-01']
valid = df_mature[(df_mature['obs_date'] >= '2023-01-01') & (df_mature['obs_date'] < '2023-07-01')]
test = df_mature[df_mature['obs_date'] >= '2023-07-01']
print('成熟样本占比:', df['mature'].mean())
print('训练/验证/测试:', len(train), len(valid), len(test))
五、误区复盘
误区一:随机切分代替时间切分。随机切分让未来信息泄漏到训练集,回测AUC虚高0.05以上,上线后迅速回落。
误区二:表现期一刀切。不同产品、不同客群的违约节奏不同,统一用90天可能漏掉长账期产品的后期风险。应按产品分层定义表现期。
误区三:忽视样本选取偏差。只取"已放款"客户建模,会遗漏被拒绝客群,导致模型在审批场景下无法直接使用。需明确模型应用场景,决定是否引入拒绝推断。
误区四:清洗时删除过多样本。过度清洗会改变客群分布,使训练集与真实客群脱节。清洗规则应记录、可复现,并评估对样本量的影响。
综上,数据准备不是建模前的杂活,而是决定时间外验证可信度的地基。把时间切片、观察期与表现期、样本选取、标签成熟度和数据清洗这五件事做扎实,后续的稳定性回测才有意义。