Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

案例:消费信贷逾期预测

本案例研究的目标是建立一个机器学习模型——决策树,以预测贷款是否发生违约。通过特征选择和数据转换,并将各个特征可视化,期望其能帮助我们进一步理解违约的情况。最后建立决策树模型,来对违约进行分类和预测。

银行在市场经济中发挥着至关重要的作用。他们决定谁能获得融资,以什么条件获得融资。而消费信贷作为银行最重要的贷款之一,主要面对消费者,通过信用卡和小额消费贷款等方式授权银行个人客户短期获得消费资金。

因为各种恶意和非恶意的原因,会发生贷款逾期未还现象。对于银行来说,运用技术手段,如何进行预测和预警就十分重要了。

信用评分算法,利用已有的客户历史数据,对违约的概率进行猜测,是银行用来决定是否应该发放贷款的方法。

images/pexels-photo-7007174.jpeg

图片来自Kindel Media

本数据集基于某银行的客户信用情况数据,目标是建立模型预测两年内是否会有90天以上的债务逾期,包含250,000个样本,每个样本包含11个属性,如下表所示

属性定义
SeriousDlqin2yrs两年内是否有90天以上债务逾期,“1”为有,“0”为无
RevolvingUtilizationOfUnsecuredLines债务余额占总信用额度比例,除房贷、车贷等分期贷款
age年龄
NumberOfTime30-59DaysPastDueNotWorse两年内有过30到59天债务逾期的次数
DebtRatio月花销(包括债务偿还和生活费)占月收入比例
MonthlyIncome月收入
NumberOfOpenCreditLinesAndLoans贷款和信用卡的总数
NumberOfTimes90DaysLate90天以上债务逾期次数
NumberRealEstateLoansOrLines抵押贷款和房贷的总数
NumberOfTime60-89DaysPastDueNotWorse两年内有过60到89天债务逾期的次数
NumberOfDependents家庭中的受赡养人数(如配偶和孩子)

该数据集的路径存储在对象datasets/cs-training.csv中,而数据集 datasets/cs-test.csv作为测试集,用来测试模型的表现。

完成不限于:

  1. 描述信贷逾期问题的背景

  2. 描述所使用数据集的变量

  3. 读取数据集,查看数据集的大小

  4. 对数据集进行描述性统计

  5. 绘制两年内是否有过90天以上的债务逾期的分布柱状图

  6. 以10岁为一个年龄段,绘制每个年龄段的收入分布情况的箱形图

  7. 讨论年龄与月花销占月收入比例对债务逾期的影响

  8. 绘制两年内是否有过90天以上的债务逾期用户的月收入分布图

  9. 对数据进行预处理(例如缺失问题)

  10. 将训练集划分为样本内(InSample)和样本外(OutOfSample)

  11. 建立决策树模型,对样本内(InSample)的样本进行训练

  12. 对样本外(OutOfSample)的数据集进行评估,并优化模型参数

  13. 使用测试集测试模型的表现

  14. 总结优点和不足

1.读取数据集文件

读取客户信用情况数据数据集,查看数据集的前几行。

import pandas as pd
df = pd.read_csv('datasets/cs-training.csv',index_col=0)
df
Loading...

为了方便之后绘图和理解变量,我们将列名从英文改成中文,简化下列名。

EN_CN_dict = {
            'SeriousDlqin2yrs': '是否逾期',              
            'RevolvingUtilizationOfUnsecuredLines': '债务余额占总信用额度比例',              
            'age': '年龄',               
            'NumberOfTime30-59DaysPastDueNotWorse':'30到59天债务逾期的次数',
            'DebtRatio': '月花销占月收入比例',
            'MonthlyIncome': '月收入',               
            'NumberOfOpenCreditLinesAndLoans': '贷款和信用卡的总数',               
            'NumberOfTimes90DaysLate': '90天以上债务逾期次数',               
            'NumberRealEstateLoansOrLines': '抵押贷款和房贷的总数',               
            'NumberOfTime60-89DaysPastDueNotWorse':'60到89天债务逾期的次数',
            'NumberOfDependents': '家庭人数',              
            }
df.columns = [EN_CN_dict[i] for i in df.columns]
df.head(5)
Loading...

2.对数据集进行描述性统计

df.describe()
Loading...

观察以上的描述性统计表格,我们发现 债务余额占总信用额度比例 这个变量的最小值为0,最大值为50708, 我们进一步绘图来观察该变量是否存在异常值。

import matplotlib.pyplot as plt 
from matplotlib_inline import backend_inline
backend_inline.set_matplotlib_formats('svg') 
plt.rcParams['font.sans-serif'] = 'Songti SC' 
plt.rcParams['axes.unicode_minus'] = False 
df['债务余额占总信用额度比例'].plot(kind='box', figsize=(8,4))
<Axes: >
Loading...
df.loc[df['债务余额占总信用额度比例']>1, '债务余额占总信用额度比例']
163 1.046279 192 1.095083 227 1.953488 252 1.048211 294 2340.000000 ... 149940 1.049900 149956 1.135552 149963 1.005733 149965 1.010934 149974 1.026395 Name: 债务余额占总信用额度比例, Length: 3321, dtype: float64

通过以上的方式,我们了解到共3321个样本在变量’债务余额占总信用额度比例’上存在异常值问题,我们 将其大于1的值修正为1。

df.loc[df['债务余额占总信用额度比例']>1, '债务余额占总信用额度比例'] = 1

接着,我们观察到变量 月花销占月收入比例 的数值也存在异常值的问题,我们对其进行修正,先将大于1的 值改为nan,再填充成均值。

import numpy as np
df.loc[df['月花销占月收入比例']>1, '月花销占月收入比例'] = np.nan
df['月花销占月收入比例'] = df['月花销占月收入比例'].fillna(df['月花销占月收入比例'].mean())

3.绘制两年内是否有过90天以上的债务逾期的分布柱状图

fig = df['是否逾期'].plot(kind='hist', title='两年内是否有过90天以上的债务逾期的分布柱状图',
                       figsize=(8,4))
Loading...

观察以上图片,我们发现样本在我们分类目标(当然也是预测目标) 两年内是否有过90天以上的债务逾期 上不 均衡,值为0的样本约为14万个,值为1的样本约为1万个。这是典型的分类不均衡的案例。

4.以10岁为一个年龄段,讨论每个年龄段的是否违约情况

df['年龄'].hist()
<Axes: >
Loading...

首先构建年龄段, 10-20, 20-30, 30-40, 40-50 ...,以10岁为一个年龄段,来绘制不同年龄段下的是否违约 的饼状图

import matplotlib.pyplot as plt
fig, ax = plt.subplots(nrows=3, ncols=3, figsize=(10,10))          #跳到下一个子图
ax = ax.flatten()                                                  #子图的2维序号变成1维序号,坐标轴ax

index = 0
for i in range(20, 110, 10):
    age_df = df.loc[np.logical_and(df['年龄']>=i, df['年龄']<i+10)] # 对年龄进行分段
    yes = (age_df['是否逾期'] == 1).sum()/len(age_df)               # 在某个年龄段内统计逾期和未逾期的比例
    no = (age_df['是否逾期'] == 0).sum()/len(age_df)
    ax[index].pie([yes, no],                                       #坐标轴ax[index]绘制饼状图
                  labels=['未逾期=%.2f' %no, '逾期=%.2f' %yes],      #标签
                  explode=[0, 0.2],                                    
                  shadow=True)                                     #阴影
    ax[index].set_title('年龄段:[%s-%s)岁' %(i, i+10))              #标题
    index += 1                                                     #跳到下一个子图
    
     
Loading...

5.讨论月花销占月收入比例对债务逾期的影响

将月花销占比月收入 这个连续型变量变成离散的,使用分段的方法,分成1-5个等级。 假说:等级越低,代表经济状况越差,其申请贷款,逾期的可能性就越高。




6.绘制两年内是否有过90天以上的债务逾期用户的月收入分布图



7.对数据进行预处理(例如缺失问题)

我们直接使用平均值对于缺失的变量进行填充。

 df = df.fillna(df.mean())

8.将训练集划分为样本内(InSample)和样本外(OutOfSample)

X = df[['债务余额占总信用额度比例', '年龄', '30到59天债务逾期的次数', '月花销占月收入比例',
        '月收入','贷款和信用卡的总数', '90天以上债务逾期次数', '抵押贷款和房贷的总数',
        '60到89天债务逾期的次数', '家庭人数']]
y = df['是否逾期']
from sklearn.model_selection import train_test_split
is_x, oos_x, is_y, oos_y = train_test_split(X, y, train_size=0.8,random_state=42)

9.建立决策树模型,对样本内(InSample)的样本进行训练

from sklearn import tree
model = tree.DecisionTreeClassifier(max_depth=3, splitter='best')
model.fit(is_x, is_y)
Loading...
model.score(is_x, is_y)
0.9354833333333333
is_x.columns.values
array(['债务余额占总信用额度比例', '年龄', '30到59天债务逾期的次数', '月花销占月收入比例', '月收入', '贷款和信用卡的总数', '90天以上债务逾期次数', '抵押贷款和房贷的总数', '60到89天债务逾期的次数', '家庭人数'], dtype=object)
from sklearn.tree import plot_tree
plt.figure(figsize=(24,6))
plot_tree(model,
          max_depth=3,
         class_names=['No', 'Yes'],
         feature_names=is_x.columns.to_list(),
          rounded=True,
          fontsize=12,
         filled=True)
plt.title('消费信贷逾期分类决策树') 
plt.show()
Loading...

10. 对样本外(OutOfSample)的数据集进行评估,并优化模型参数

model.score(oos_x, oos_y)
0.9365

11. 使用测试集测试模型的表现



12. 总结优点和不足