贷款数据的类别不平衡

Python 信用风险建模

Michael Crabtree

Data Scientist, Ford Motor Company

数据中违约过少

  • loan_status 的取值即为类别
    • 非违约:0
    • 违约:1
y_train['loan_status'].value_counts()
loan_status 训练集计数 占比
0 13,798 78%
1 3,877 22%
Python 信用风险建模

模型的损失函数

  • xgboost 的梯度提升树使用对数损失(log-loss)
    • 目标是最小化该值

对数损失公式

实际状态 预测概率 对数损失
1 0.1 2.3
0 0.9 2.3
  • 误判违约的财务影响更大
Python 信用风险建模

不平衡的成本

  • 假阴性(将违约预测为非违约)成本更高得多
人员 贷款额 潜在利润 预测状态 实际状态 损失
A $1,000 $10 违约 非违约 -$10
B $1,000 $10 非违约 违约 -$1,000
  • 两者的对数损失相同,但实际损失不同
Python 信用风险建模

不平衡的原因

  • 数据问题:
    • 信贷数据抽样不当
    • 数据存储问题
  • 业务流程:
    • 已有措施拒绝高违约概率的申请
    • 高违约概率的贷款被迅速转售
  • 行为因素:
    • 大多数人通常不会违约
      • 违约越少,信用评分越高
Python 信用风险建模

应对类别不平衡

  • 处理类别不平衡的多种方法
方法 优点 缺点
收集更多数据 提高违约数量 违约占比可能不变
对模型加惩罚 提升违约召回率 需要更多调参与维护
不同方式采样 技术改动最少 数据中违约更少
Python 信用风险建模

欠采样策略

  • 将较小的随机非违约样本与违约样本合并

欠采样策略示意图

Python 信用风险建模

合并拆分的数据集

  • 需将测试集与训练集合并
  • 根据实际 loan_status 创建两个新集合
# Concat the training sets
X_y_train = pd.concat([X_train.reset_index(drop = True),
                       y_train.reset_index(drop = True)], axis = 1)
# Get the counts of defaults and non-defaults
count_nondefault, count_default = X_y_train['loan_status'].value_counts()
# Separate nondefaults and defaults
nondefaults = X_y_train[X_y_train['loan_status'] == 0]
defaults = X_y_train[X_y_train['loan_status'] == 1]
Python 信用风险建模

对非违约进行欠采样

  • 随机抽取非违约数据子集
  • 与违约数据集拼接
# Undersample the non-defaults using sample() in pandas
nondefaults_under = nondefaults.sample(count_default)
# Concat the undersampled non-defaults with the defaults
X_y_train_under = pd.concat([nondefaults_under.reset_index(drop = True),
                             defaults.reset_index(drop = True)], axis=0)
Python 信用风险建模

让我们练习!

Python 信用风险建模

Preparing Video For Download...