4. 数据采集与清洗:数据来源、质量检查与预处理

信用评分模型的质量高度依赖输入数据的准确性与完整性。本章聚焦于数据采集的三大来源、数据质量检查的核心维度,以及缺失值与异常值的标准化处理方法。数据清洗是人群分层信用定价的基石,直接影响后续分箱、评分卡构建与定价策略的有效性。

4.1 数据来源:银行与第三方征信

信用评分建模所需数据主要来自两类渠道:银行内部数据与第三方征信数据。两类数据在覆盖度、时效性与合规要求上存在显著差异,需在采集阶段明确其适用场景。

数据来源 典型字段 优势 局限性
银行内部 还款记录、账户余额、交易流水、存款/理财持有量 高准确性、强关联性、可追溯 覆盖仅限本行客户,新客缺失
第三方征信 多头借贷、逾期黑名单、社保/公积金、电商消费 跨机构覆盖、补充弱变量 数据标准不一、更新延迟、合规成本高
政府/公共数据 法院执行、税务、工商注册 权威性高、不可伪造 查询频率受限、字段稀疏
实务建议:在人群分层信用定价中,建议优先融合银行内部还款行为数据与第三方多头借贷指标。前者刻画还款意愿,后者反映负债压力,两者结合可显著提升风险区分度。

4.2 数据质量检查:六大核心维度

数据采集完成后,必须执行系统性质量检查。以下六个维度是信用评分建模的标准检查清单:

  1. 完整性:检查字段缺失率,重点关注收入、负债、逾期天数等关键变量。
  2. 准确性:验证字段值是否在合理范围内(如年龄 0-120、逾期天数 ≥ 0)。
  3. 一致性:跨表或跨时间点的同一字段值是否逻辑自洽(如贷款余额 ≤ 授信额度)。
  4. 时效性:数据采集时间是否在建模窗口期内(通常为近 6-12 个月)。
  5. 唯一性:客户标识(如身份证号)是否存在重复记录。
  6. 合规性:是否包含敏感字段(如种族、宗教信仰),需按监管要求脱敏或剔除。
质量检查清单示例:建议在数据采集后生成一份 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,记录每一步删除/填充/截尾的样本量与字段名,确保模型可复现且符合监管审计要求。