数据准备与特征工程:催收数据集清洗、缺失值处理、异常值检测、衍生变量构造

催收评分卡(Collection Score)的预测能力高度依赖底层数据的质量与特征表达能力。原始催收数据集通常包含大量噪声、缺失值、异常记录以及冗余字段,直接建模会导致模型偏差大、稳定性差。本章系统讲解催收数据集从清洗到特征工程的标准流程,确保后续建模阶段的数据基础可靠、特征维度丰富。

2.1 催收数据集清洗

数据清洗是特征工程的第一步,核心目标是消除重复记录、纠正格式错误、统一字段标准。催收数据常见的脏数据包括:

  • 重复案件:同一笔逾期贷款在催收系统中被多次录入,导致样本权重失衡。
  • 字段格式不一致:如日期字段混用“YYYY-MM-DD”与“YYYY/MM/DD”,金额字段包含逗号或货币符号。
  • 逻辑矛盾:如“逾期天数”为负值,“已还金额”大于“应还总额”。
  • 无效分类值:如“催收状态”字段出现未定义的编码或拼写错误。
实操建议:清洗阶段建议保留原始数据副本,所有清洗操作通过脚本记录,确保可追溯。对于逻辑矛盾记录,优先与业务系统核对;无法核对的,标记为“待确认”而非直接删除。

2.2 缺失值处理

催收数据中缺失值普遍存在,常见原因包括:客户未提供信息、系统采集遗漏、字段非必填项。缺失值处理策略需结合字段类型与缺失比例综合判断。

缺失比例 数值型字段 分类型字段 时间型字段
< 5% 中位数填充 / 均值填充 众数填充 前向填充(按客户ID)
5% – 30% 模型预测填充(如KNN、随机森林) 新增“未知”类别 标记为缺失,保留缺失指示变量
> 30% 删除该字段,或构造“是否缺失”二值变量后保留 删除该字段,或合并为“其他”类别 删除该字段
关键原则:缺失值填充不应引入未来信息。例如,使用全量数据均值填充会导致训练集与测试集信息泄露。推荐在交叉验证折内分别计算填充统计量,或使用时间序列窗口内的统计值。

2.3 异常值检测

异常值在催收数据中通常表现为极端逾期金额、异常短的催收间隔、或不合逻辑的客户年龄。异常值检测方法需根据数据分布特征选择。

  • Z-Score 方法:适用于近似正态分布的字段,如“客户年龄”、“历史贷款笔数”。通常取 |Z| > 3 为异常。
  • IQR 四分位距法:适用于偏态分布字段,如“逾期金额”、“催收通话时长”。定义下界 Q1 - 1.5×IQR,上界 Q3 + 1.5×IQR。
  • 业务规则法:基于催收业务常识设定阈值,如“单日催收通话次数 > 50”视为异常。
注意:异常值不一定是错误值。例如,一笔大额企业贷款逾期金额远高于个人贷款,但属于正常业务场景。建议对检测出的异常值进行业务复核,区分“自然极端值”与“数据错误值”,前者可保留或做截尾处理,后者应修正或删除。

2.4 衍生变量构造

原始字段的预测能力有限,通过业务理解与统计变换构造衍生变量,是提升催收评分卡区分度的关键。衍生变量主要分为以下几类:

催收衍生变量构造体系 衍生变量构造 时间窗口统计类 比率与占比类 趋势与波动类 交叉组合类 近30天催收次数 近7天通话时长 历史承诺还款次数 已还金额 / 应还总额 接通次数 / 拨打次数 逾期天数变化斜率 催收金额标准差 逾期天数 × 贷款金额 催收渠道 × 时段

2.5 特征工程代码示例

以下代码展示催收数据特征工程的核心步骤,包括缺失值填充、异常值截尾、以及衍生变量构造:

import pandas as pd
import numpy as np

# 加载清洗后的催收数据
df = pd.read_csv('collection_data_clean.csv')

# ========== 缺失值处理 ==========
# 数值型字段:用中位数填充
num_cols = ['overdue_amount', 'call_duration', 'total_loans']
for col in num_cols:
    median_val = df[col].median()
    df[col].fillna(median_val, inplace=True)

# 分类型字段:用众数填充,并保留缺失指示变量
cat_cols = ['contact_channel', 'customer_occupation']
for col in cat_cols:
    df[col + '_is_missing'] = df[col].isnull().astype(int)
    mode_val = df[col].mode()[0]
    df[col].fillna(mode_val, inplace=True)

# ========== 异常值截尾处理 ==========
# 对逾期金额做 99% 分位数截尾
upper_limit = df['overdue_amount'].quantile(0.99)
df['overdue_amount'] = df['overdue_amount'].clip(upper=upper_limit)

# ========== 衍生变量构造 ==========
# 时间窗口统计:近30天催收次数
df['call_count_30d'] = df.groupby('customer_id')['call_date'].transform(
    lambda x: x.rolling('30D', min_periods=1).count()
)

# 比率变量:还款完成率
df['repayment_rate'] = df['paid_amount'] / (df['total_due'] + 1e-6)

# 交叉组合:逾期天数 × 贷款金额(风险暴露度)
df['risk_exposure'] = df['overdue_days'] * df['loan_amount']

# 趋势变量:逾期天数变化斜率(近3次催收记录)
df['overdue_trend'] = df.groupby('customer_id')['overdue_days'].transform(
    lambda x: x.diff().rolling(3, min_periods=1).mean()
)

print("特征工程完成,衍生变量数量:", df.shape[1])
工程要点:衍生变量构造后务必检查新字段的缺失率与分布。例如,overdue_trend 在只有单次催收记录的客户中会全部为 NaN,需决定是否填充为 0 或删除该部分样本。建议在建模前对全部衍生变量做一次相关性分析,剔除高度共线特征(|r| > 0.95)。

2.6 特征工程质量检查清单

完成特征工程后,建议按以下清单逐项确认数据质量:

检查项 验收标准 常见问题
缺失率 所有字段缺失率 < 30% 衍生变量因计算窗口不足产生大量缺失
异常值 数值字段无极端离群点(超出 3σ 或 1.5×IQR) 截尾后仍存在业务上不合理的值
数据分布 连续变量偏度 |Skew| < 2,峰度 Kurtosis < 5 长尾分布未做对数变换或 Box-Cox 变换
共线性 VIF(方差膨胀因子)< 10 时间窗口变量与原始变量高度相关
业务逻辑 衍生变量含义可解释,无未来信息泄露 使用了全量数据统计值填充训练集

通过以上数据准备与特征工程流程,催收数据集将从原始杂乱状态转变为结构清晰、特征丰富、适合建模的高质量数据集,为后续 Collection Score 模型开发奠定坚实基础。