4. 数据采集与清洗:数据来源、质量检查与预处理
信用评分模型的质量高度依赖输入数据的准确性与完整性。本章聚焦于数据采集的三大来源、数据质量检查的核心维度,以及缺失值与异常值的标准化处理方法。数据清洗是人群分层信用定价的基石,直接影响后续分箱、评分卡构建与定价策略的有效性。
4.1 数据来源:银行与第三方征信
信用评分建模所需数据主要来自两类渠道:银行内部数据与第三方征信数据。两类数据在覆盖度、时效性与合规要求上存在显著差异,需在采集阶段明确其适用场景。
| 数据来源 | 典型字段 | 优势 | 局限性 |
|---|---|---|---|
| 银行内部 | 还款记录、账户余额、交易流水、存款/理财持有量 | 高准确性、强关联性、可追溯 | 覆盖仅限本行客户,新客缺失 |
| 第三方征信 | 多头借贷、逾期黑名单、社保/公积金、电商消费 | 跨机构覆盖、补充弱变量 | 数据标准不一、更新延迟、合规成本高 |
| 政府/公共数据 | 法院执行、税务、工商注册 | 权威性高、不可伪造 | 查询频率受限、字段稀疏 |
实务建议:在人群分层信用定价中,建议优先融合银行内部还款行为数据与第三方多头借贷指标。前者刻画还款意愿,后者反映负债压力,两者结合可显著提升风险区分度。
4.2 数据质量检查:六大核心维度
数据采集完成后,必须执行系统性质量检查。以下六个维度是信用评分建模的标准检查清单:
- 完整性:检查字段缺失率,重点关注收入、负债、逾期天数等关键变量。
- 准确性:验证字段值是否在合理范围内(如年龄 0-120、逾期天数 ≥ 0)。
- 一致性:跨表或跨时间点的同一字段值是否逻辑自洽(如贷款余额 ≤ 授信额度)。
- 时效性:数据采集时间是否在建模窗口期内(通常为近 6-12 个月)。
- 唯一性:客户标识(如身份证号)是否存在重复记录。
- 合规性:是否包含敏感字段(如种族、宗教信仰),需按监管要求脱敏或剔除。
质量检查清单示例:建议在数据采集后生成一份
data_quality_report.csv,逐字段记录缺失率、异常值比例、最大值/最小值、唯一值数量,作为清洗前的基线文档。
4.3 缺失值处理策略
缺失值是信用数据中的常见问题。处理策略需根据缺失机制(完全随机缺失、随机缺失、非随机缺失)与变量重要性综合选择。以下为三种主流方法:
| 处理方法 | 适用场景 | 实现方式 | 注意事项 |
|---|---|---|---|
| 删除法 | 缺失率 > 70% 或随机缺失 | 删除字段或样本行 | 避免删除过多样本导致样本偏差 |
| 填充法 | 缺失率 < 30%,变量有业务含义 | 均值/中位数/众数填充;或使用模型预测填充 | 连续变量用中位数更稳健;分类变量用众数 |
| 标记法 | 缺失本身具有信息量(如未查询到征信) | 新增“是否缺失”二值变量,原值用 -1 或 0 填充 | 常用于多头借贷、收入等字段 |
避坑提示:在信用评分建模中,切勿对“逾期天数”等关键风险变量使用均值填充。缺失的逾期天数往往代表“未逾期”,应优先使用 0 填充或标记法,否则会严重扭曲风险排序。
4.4 异常值处理:识别与修正
异常值可能源于数据录入错误、系统故障或真实的极端风险事件。处理前需先识别,再根据业务含义决定修正或保留。
4.4.1 异常值识别方法
- 统计法:基于四分位距(IQR),超出 Q1-1.5×IQR 或 Q3+1.5×IQR 视为异常。
- 业务规则法:如年龄 > 100 岁、月收入 > 1000 万、逾期天数 > 1800 天等。
- 模型法:使用孤立森林(Isolation Forest)或 DBSCAN 聚类检测多维异常。
4.4.2 异常值处理策略
| 处理方式 | 操作 | 适用场景 |
|---|---|---|
| 截尾(Winsorize) | 将异常值替换为 1% 或 99% 分位数 | 连续变量如收入、负债率 |
| 删除 | 直接移除异常样本 | 明显录入错误(如年龄 200 岁) |
| 单独分箱 | 将异常值归为独立类别 | 分类变量或业务上认为异常值有风险含义 |
4.5 数据清洗代码示例(Python)
以下代码展示了缺失值与异常值处理的典型实现,适用于信用评分建模前的数据预处理阶段。
import pandas as pd
import numpy as np
# 加载数据
df = pd.read_csv('credit_data.csv')
# 4.5.1 缺失值处理
# 删除缺失率 > 70% 的字段
threshold = 0.7
df = df.loc[:, df.isnull().mean() < threshold]
# 连续变量用中位数填充
for col in ['income', 'debt_ratio']:
df[col].fillna(df[col].median(), inplace=True)
# 分类变量用众数填充,并新增缺失标记
df['has_credit_inquiry'] = df['credit_inquiry_count'].isnull().astype(int)
df['credit_inquiry_count'].fillna(0, inplace=True)
# 4.5.2 异常值处理(截尾法)
def winsorize_series(s, lower=0.01, upper=0.99):
q_low = s.quantile(lower)
q_high = s.quantile(upper)
return s.clip(lower=q_low, upper=q_high)
df['income_winsorized'] = winsorize_series(df['income'])
# 4.5.3 业务规则异常值删除
df = df[df['age'].between(18, 100)]
df = df[df['overdue_days'] >= 0]
print(f"清洗后数据形状: {df.shape}")
print(f"缺失值比例:\n{df.isnull().mean().sort_values(ascending=False)}")
关键提醒:数据清洗完成后,务必生成一份
data_cleaning_log.md,记录每一步删除/填充/截尾的样本量与字段名,确保模型可复现且符合监管审计要求。