3. 数据准备与特征工程:数据清洗、缺失值处理、异常值检测、特征分箱与WOE编码
在信用评分模型开发中,数据准备与特征工程占据整个项目60%以上的工作量。原始信贷数据通常包含噪声、缺失、异常以及非线性关系,直接建模会导致模型不稳定、区分能力下降。本节将系统讲解从原始数据到建模特征的核心处理流程。
3.1 数据清洗:构建高质量样本的基础
数据清洗的目标是消除原始数据中的格式错误、逻辑矛盾与重复记录,确保后续处理的可靠性。
| 清洗类型 | 常见问题 | 处理方法 |
|---|---|---|
| 格式统一 | 日期格式不一致(2024/01/01 vs 2024-01-01) | 统一转换为标准日期格式 |
| 逻辑校验 | 年龄为负数、贷款金额为0 | 结合业务规则剔除或修正 |
| 重复记录 | 同一客户多次申请,ID重复 | 按申请时间保留最新记录 |
| 异常字符 | 数值字段包含字母、特殊符号 | 正则匹配清洗或置为缺失 |
实战提示:在清洗阶段保留原始字段副本,建立数据血缘记录。每次清洗操作都应有明确的业务规则文档,避免"黑箱清洗"导致模型上线后无法追溯数据问题。
3.2 缺失值处理:平衡信息损失与偏差
信贷数据中缺失值普遍存在,处理方式直接影响模型性能。根据缺失机制(MCAR、MAR、MNAR)选择合适策略。
- 删除法:当缺失比例低于5%且为随机缺失时,可直接删除缺失样本或特征。
- 均值/中位数填充:适用于数值型特征,简单快速但会降低方差。
- 众数填充:适用于分类型特征,如婚姻状况、学历等级。
- 模型预测填充:使用KNN、随机森林等算法预测缺失值,精度高但计算成本大。
- 缺失值单独成类:将缺失视为一个独立类别,特别适合WOE编码场景。
信用评分最佳实践:对于信贷申请数据,建议将缺失值单独作为一个分箱类别参与WOE编码。这种方式保留了缺失样本的分布信息,且不会引入填充偏差,在评分卡建模中表现稳定。
3.3 异常值检测:识别极端风险样本
异常值在信用评分中可能代表欺诈申请或极端风险客户,需要谨慎处理。
注意:不要机械地删除所有异常值。在信用评分中,某些"异常"客户(如超高收入、极低负债率)可能是优质客户,直接删除会损失模型对好客户的区分能力。建议先分箱观察异常值所在箱的坏账率,再决定处理方式。
3.4 特征分箱:捕捉非线性关系
特征分箱是将连续变量或离散变量划分为若干区间(箱),是评分卡建模的核心步骤。分箱质量直接影响WOE编码效果和模型稳定性。
常用分箱方法
| 分箱方法 | 原理 | 优点 | 缺点 |
|---|---|---|---|
| 等距分箱 | 按数值范围均匀划分 | 简单直观 | 样本分布不均,空箱风险 |
| 等频分箱 | 每箱包含相同样本数 | 箱内样本均衡 | 边界值可能不自然 |
| 决策树分箱 | 用单变量决策树寻找最优切分点 | 自动捕捉非线性 | 过拟合风险 |
| 卡方分箱 | 基于卡方检验合并相邻区间 | 统计显著性驱动 | 计算复杂度较高 |
分箱原则:每个箱至少包含5%的样本;坏账率(Bad Rate)在相邻箱之间应呈现单调性;箱数控制在5~10个之间;特殊值(如0、缺失)单独成箱。
3.5 WOE编码:将分箱转化为模型输入
WOE(Weight of Evidence,证据权重)是评分卡模型中最常用的特征编码方式,将分箱后的类别转化为反映好坏客户分布差异的数值。
WOE计算公式
WOE_i = ln( (Bad_i / Bad_total) / (Good_i / Good_total) )
其中:
- Bad_i = 第i个箱中的坏客户数
- Good_i = 第i个箱中的好客户数
- Bad_total = 全部坏客户数
- Good_total = 全部好客户数
WOE编码的核心优势
- 线性化处理:将非线性关系转化为线性关系,适配逻辑回归模型。
- 缺失值包容:缺失值作为独立箱参与编码,无需额外填充。
- 异常值鲁棒:极端值被分箱吸收,不会过度影响模型。
- 业务可解释:WOE正值表示该箱好客户占比更高,负值表示坏客户占比更高。
WOE编码的Python实现
import pandas as pd
import numpy as np
def woe_encode(df, feature, target, bins=5):
"""
对特征进行分箱并计算WOE编码
Parameters:
df: DataFrame,包含特征和目标变量
feature: str,特征名称
target: str,目标变量名称(0=好客户,1=坏客户)
bins: int,分箱数量
Returns:
woe_dict: dict,每个箱对应的WOE值
"""
# 等频分箱
df['bin'] = pd.qcut(df[feature], q=bins, duplicates='drop')
# 计算每个箱的好坏分布
grouped = df.groupby('bin')[target].agg(['count', 'sum'])
grouped.columns = ['total', 'bad']
grouped['good'] = grouped['total'] - grouped['bad']
# 计算WOE
total_bad = grouped['bad'].sum()
total_good = grouped['good'].sum()
grouped['bad_pct'] = grouped['bad'] / total_bad
grouped['good_pct'] = grouped['good'] / total_good
grouped['woe'] = np.log(grouped['good_pct'] / grouped['bad_pct'])
# 处理无穷值
grouped['woe'] = grouped['woe'].replace([np.inf, -np.inf], 0)
return grouped['woe'].to_dict()
实战技巧:WOE编码完成后,建议计算每个特征的IV值(Information Value,信息量)来评估特征区分能力。IV < 0.02为弱特征,0.02~0.1为中等,0.1~0.3为强特征,> 0.5需警惕过拟合。
3.6 本章小结
数据准备与特征工程是信用评分模型成败的关键环节。数据清洗确保数据质量,缺失值处理平衡信息损失,异常值检测识别极端风险,特征分箱捕捉非线性关系,WOE编码将分箱结果转化为线性模型可用的数值特征。每一步都需要结合业务逻辑和数据分布做出合理决策,而非机械套用统计方法。