4. 数据准备与探索
在LightGBM信用评分建模中,数据准备与探索决定了模型性能的上限。信用评分本质上是一个二分类问题:预测借款人未来是否违约。与一般机器学习任务不同,信贷数据具有强业务属性、高维度、缺失普遍、样本不平衡和分布漂移等特征。本章围绕数据来源、缺失值处理、异常值检测、类别不平衡分析和特征分布可视化五个环节,建立可复用的数据准备流程。
一、信贷数据来源与业务理解
信贷数据通常来自三类渠道:申请端数据(申请表、身份信息、收入证明)、行为端数据(还款记录、账户流水、消费行为)和外部数据(征信报告、多头借贷、司法信息)。建模时需明确观察期、表现期和观察时点,避免时间穿越。例如,用2023年1月至6月申请样本,观察其未来12个月是否发生90天以上逾期,标签定义为1(违约)或0(正常)。
二、缺失值处理:从诊断到填充
信贷数据缺失往往具有信息量。例如,“无征信记录”本身可能意味着薄信用人群,直接删除会引入偏差。处理流程如下:
- 缺失诊断:统计每列缺失率,区分完全随机缺失、随机缺失和非随机缺失。
- 缺失标记:对缺失率高于5%的字段,生成二值指示列,保留缺失模式信息。
- 填充策略:数值型用中位数或分位数填充,类别型用“MISSING”单独成类;LightGBM可直接处理缺失值,但显式标记通常更稳定。
- 缺失率过滤:缺失率超过80%且业务解释弱的字段可考虑剔除。
import pandas as pd
import numpy as np
def missing_report(df, threshold=0.05):
miss = df.isnull().mean().sort_values(ascending=False)
report = pd.DataFrame({'missing_rate': miss})
report['need_flag'] = report['missing_rate'] > threshold
return report
# 对高缺失字段生成缺失指示列
for col in ['credit_score', 'income']:
if df[col].isnull().mean() > 0.05:
df[f'{col}_is_missing'] = df[col].isnull().astype(int)
df[col] = df[col].fillna(df[col].median())
三、异常值检测:业务规则与统计方法结合
异常值在信贷数据中既可能是录入错误,也可能是真实高风险信号。例如,年龄为200岁是错误,但月收入为0可能代表失业,具有预测价值。建议采用“统计检测+业务复核”双轨制:
- 统计方法:IQR法、Z-Score、分位数截断,适用于连续变量。
- 业务规则:年龄<18或>100、收入为负、负债收入比异常高等直接标记。
- 处理方式:对错误值修正或置为缺失;对真实极端值保留,必要时做Winsorize缩尾。
def detect_outliers_iqr(series):
q1, q3 = series.quantile([0.25, 0.75])
iqr = q3 - q1
lower, upper = q1 - 1.5 * iqr, q3 + 1.5 * iqr
return (series < lower) | (series > upper)
# 对收入做缩尾处理,保留极端但不过度影响模型
df['income'] = df['income'].clip(
lower=df['income'].quantile(0.01),
upper=df['income'].quantile(0.99)
)
四、类别不平衡分析与特征分布可视化
信贷违约样本通常占比1%~10%,属于典型类别不平衡。若直接训练,模型会偏向多数类,导致召回率低。分析步骤包括:统计标签分布、计算不平衡比、评估不同采样策略对验证集的影响。LightGBM可通过scale_pos_weight或is_unbalance参数调节,但更推荐在交叉验证中对比效果。
| 环节 | 常用方法 | 注意事项 |
|---|---|---|
| 缺失值 | 中位数填充、缺失指示列、模型原生处理 | 保留缺失模式,避免信息丢失 |
| 异常值 | IQR、Z-Score、业务规则、Winsorize | 区分错误值与真实风险信号 |
| 不平衡 | scale_pos_weight、SMOTE、欠采样 | 只在训练集采样,验证集保持原始分布 |
| 分布可视化 | 直方图、箱线图、KS曲线、PSI | 关注训练集与验证集分布一致性 |
特征分布可视化是发现数据问题的关键手段。对连续变量绘制直方图和箱线图,对类别变量绘制违约率柱状图。特别要关注训练集与验证集的分布差异,可用PSI(群体稳定性指数)量化。若某特征PSI>0.1,说明分布发生显著漂移,需检查样本时间窗口或特征口径。
import matplotlib.pyplot as plt
def plot_distribution(df, col, target='label'):
fig, axes = plt.subplots(1, 2, figsize=(12, 4))
df[col].hist(bins=30, ax=axes[0])
axes[0].set_title(f'{col} distribution')
df.groupby(col)[target].mean().plot(ax=axes[1])
axes[1].set_title(f'{col} vs default rate')
plt.tight_layout()
plt.show()
# 计算PSI
def psi(expected, actual, bins=10):
breakpoints = np.percentile(expected, np.linspace(0, 100, bins + 1))
expected_perc = np.histogram(expected, breakpoints)[0] / len(expected)
actual_perc = np.histogram(actual, breakpoints)[0] / len(actual)
expected_perc = np.where(expected_perc == 0, 0.0001, expected_perc)
actual_perc = np.where(actual_perc == 0, 0.0001, actual_perc)
return np.sum((expected_perc - actual_perc) * np.log(expected_perc / actual_perc))
五、常见误区与复盘
实践中常见误区包括:用全局统计量填充缺失值导致数据泄漏;在划分训练验证集之前做采样;对类别变量直接做均值编码而未做交叉验证;忽略时间维度导致未来信息泄露。复盘时应重点检查:标签定义是否与业务一致、缺失处理是否在训练集上拟合、异常值处理是否可复现、不平衡策略是否只在训练集生效、分布可视化是否覆盖关键特征。只有把数据准备做扎实,LightGBM才能输出稳定可靠的信用评分与校准概率。