当前位置:   article > 正文

【机器学习】数据挖掘实战:个人信贷违约预测

基于机器学习的信贷违约风险预测

本次分享风控圈子的一个练手实战项目:个人信贷违约预测,此项目对于想要学习信贷风控模型的同学非常有帮助。

3f425f6aeb5b8474e0c9e0c9db1e9936.png

项目背景

当今社会,个人信贷业务发展迅速,但同时也会暴露较高的信用风险。信息不对称在金融贷款领域突出,表现在过去时期借款一方对自身的财务状况、还款能力及还款意愿有着较为全面的掌握,而金融机构不能全面获知借款方的风险水平,或在相关信息的掌握上具有明显的滞后性。这种信息劣势,使得金融机构在贷款过程中可能由于风险评估与实际情况的偏离,产生资金损失,直接影响金融机构的利润水平。

而现今时间金融机构可以结合多方数据,提前对客户风险水平进行评估,并做出授信决策。

解决方法

运用分类算法预测违约

模型选择

单模型: 决策树、贝叶斯、SVM等
集成模型: 随机森林、梯度提升树等
评分卡模型: 逻辑回归
项目可输出: 评分卡

数据描述

数据总体概述

可用的训练数据包括用户的基本属性user_info.txt、银行流水记录bank_detail.txt、用户浏览行为browse_history.txt、信用卡账单记录bill_detail.txt、放款时间loan_time.txt,以及这些顾客是否发生逾期行为的记录overdue.txt。(注意:并非每一位用户都有非常完整的记录,如有些用户并没有信用卡账单记录,有些用户却没有银行流水记录。)

相应地,还有用于测试的用户的基本属性、银行流水、信用卡账单记录、浏览行为、放款时间等数据信息,以及待预测用户的id列表。

脱敏处理:(a) 隐藏了用户的id信息;(b) 将用户属性信息全部数字化;(c) 将时间戳和所有金额的值都做了函数变换。

(1)用户的基本属性user_info.txt。共6个字段,其中字段性别为0表示性别未知。

用户id,性别,职业,教育程度,婚姻状态,户口类型   6346,1,2,4,4,2

(2)银行流水记录bank_detail.txt。共5个字段,其中,第2个字段,时间戳为0表示时间未知;第3个字段,交易类型有两个值,1表示支出、0表示收入;第5个字段,工资收入标记为1时,表示工资收入。

用户id,时间戳,交易类型,交易金额,工资收入标记   6951,5894316387,0,13.756664,0

(3)用户浏览行为browse_history.txt。共4个字段。其中,第2个字段,时间戳为0表示时间未知。

用户id,时间戳,浏览行为数据,浏览子行为编号   34724,5926003545,172,1

(4)信用卡账单记录bill_detail.txt。共15个字段,其中,第2个字段,时间戳为0表示时间未知。为方便浏览,字段以表格的形式给出。

5700a9d63e42316fa558ce78239ef293.jpeg

(6)顾客是否发生逾期行为的记录overdue.txt。共2个字段。样本标签为1,表示逾期30天以上;样本标签为0,表示逾期10天以内。

注意:逾期10天~30天之内的用户,并不在此问题考虑的范围内。用于测试的用户,只提供id列表,文件名为testUsers.csv。

用户id,样本标签   1,1   2,0   3,1

各个数据表之间的关系

0bccf6f478c926353e79da794098a4a3.png

数据预处理

从表中数据得知并非每一位用户都有非常完整的记录,如有些用户并没有信用卡账单记录,有些用户却没有银行流水记录。

发现用户信息表,是否逾期表,放款时间表这三张表的id数目都是55,596,银行流水表为9,294,浏览信息表为47,330,信用卡账单表为53,174。通过用户id数得到并非每个用户都有银行流水记录、信用卡账单等信息,所以这里我们取6个表共同用户的记录筛选后组成完整的表。

我们要预测的测试集都是还没有放款的用户特征,所以训练数据这里我们也选取放款时间之前的特征,将存在时间戳的表与放款时间表进行交叉,只筛选此时间范围内的用户id

筛选出这6张表共有的用户id,得出5735个用户的记录是完整的。

user.T
a41ca267d9ce69ab8061b1f6e6f0d94d.png

银行账单表

  1. bank_detail_select = pd.merge(left=df_bank_detail_train, 
  2.                               right=user, 
  3.                               how='inner'
  4.                               on='用户id')
f3c1cf6676363356f2ae6fb328ba53d6.png

统计用户进账单数,求和

6df5785f62fac9cea09fd31a14e10c1b.png

统计用户支出单数,求和

8a14d821e0db727236f7038f3bb7e121.png

统计用户工资收入计数,求和

1980406f16b05609c70e6fefae7b8bb5.png

银行账单表

bank_train.head()
c46dc608b94337db10253c3cb22973e0.png

浏览表

先剔除5735以外的数据,再统计每个用户的浏览记录(count)

browse_train.head()
5495907f6d472787de4a4f2b02fc8cbd.png

账单表

去掉了时间、银行id、还款状态这几个变量,按用户id分组后对每个字段均值化处理。

14df782545e1fdd6fc931a4a336da488.png

逾期表、用户表

fd019e06f5ec1e156e1deddc20d92466.png

合并五张表

将筛选后的五个表进行合并,得出25个字段

  1. df_train=user_train.merge(bank_train)
  2. df_train=df_train.merge(bill_train)
  3. df_train=df_train.merge(browse_train)
  4. df_train=df_train.merge(overdue_train)
  5. df_train.head()
21300ebb4dbbe10941093c0060de7834.png

查看完整表格的基本情况,无缺失值,均是数值类型。

df_train.info()
b6649d4b16c53a3c44c13122c4517212.png

特征工程

基于业务理解的筛选

银行流水记录特征相关性分析

  1. # 相关性结果数据表
  2. corrmat=bank_train[internal_chars].corr()  
  3. #热力图
  4. sns.heatmap(corrmat, square=True, 
  5.             linewidths=.5, annot=True);
a4e9eabb1a7a34ba7416785863632bfc.png
  • '进账单数'与'进账金额'的相关系数很高,相关系数为0.99

  • '支出单数', '支出金额'的相关性较高,相关系数分别为0.82,0.85

  • '进账金额'与'支出单数', '支出金额'的相关性较高,相关系数分别为0.81,0.85

  • '支出单数'与 '支出金额'的相关性很高,相关系数为0.99

  • '工资笔数'与'工资收入'相关系数为1

  • 可见收入、支出、工资三个指标的金额跟笔数是线性关系,那么后续将构建一个新的特征:笔均=金额/笔数,取工资笔均;而且收入、支出是强相关(0.82),所以只取一个即可,支出笔均。

  • 后续将用'进账金额/进账单数','支出金额/支出单数','工资收入/工资笔数'得到'进账笔均','支出笔均','工资笔均'

总表相关性分析

  1. # 相关性结果数据表
  2. corrmat=df_train[internal_chars].corr()
  3. # 热力图
  4. sns.heatmap(corrmat, square=False, 
  5.             linewidths=.5, annot=True);
cab62e40997d05b0ae4bd2132b515df7.png
  • '本期账单金额'与'本期账单余额'相关系数为0.85

  • '上期账单金额'与'上期还款金额'相关系数为0.75

  • '本期账单金额'与'上期还款金额'相关系数为0.64

  • '信用卡额度'与'上期账单金额'和'上期还款金额'相关系数分别为0.54和0.52

  • '本期账单金额'与'上期账单金额'相关系数为0.5

本期的账单余额与最低还款额具有高度共线性,决定只选用最低还款额。

生产衍射变量

上期还款差额 =上期账单金额 - 上期还款金额, 上期还款差额还会直接影响用户的信用额度以及本期的账单金额。

调整金额和循环利息是跟“上期的还款差额”有关的:

  • 还款差额>0,需要计算循环利息,调整金额不计

  • 还款差额<0,需要计算调整金额,循环利息不计

可以将还款差额进行“特征二值化”来代替这两个特征。

预借现金额度,是指持卡人使用信用卡通过ATM等自助终端提取现金的最高额度,取现额度包含于信用额度之内,一般是信用额度的50%左右,所以可以不用这个特征,选择信用额度即可。

  1. df_train['平均支出']=df_train.apply(lambda x:x.支出金额/x.支出单数, axis=1)  
  2. df_train['平均工资收入']=df_train.apply(lambda x:x.工资收入/x.工资笔数, axis=1)
  3. df_train['上期还款差额']=df_train.apply(lambda x:x.上期账单金额-x.上期还款金额, axis=1)
  4. df_select=df_train.loc[:,['用户id''性别''教育程度''婚姻状态''平均支出',
  5.                           '平均工资收入''上期还款差额''信用卡额度''本期账单余额''本期账单最低还款额'
  6.                           '消费笔数',  '浏览行为数据''样本标签']].fillna(0)
  7. df_select.head()
2e522d75381a918187c114b64873f71a.png

基于机器学习的筛选

上期还款差额二值化

  1. from sklearn.preprocessing import Binarizer
  2. X=df_select['上期还款差额'].values.reshape(-1,1)
  3. transformer = Binarizer(threshold=0).fit_transform(X)
  4. df_select['上期还款差额标签']=transformer

方差过滤法

过滤那些不带有信息的变量,默认参数为0,即过滤方差为0的那些变量,只保留对模型有贡献的那些信息。

  1. from sklearn.feature_selection import VarianceThreshold
  2. VTS = VarianceThreshold()   # 实例化,参数默认方差为0
  3. x_01=VTS.fit_transform(x)

相关性过滤--互信息法

互信息法是用来捕捉每个特征与标签之间的任意关系(包括线性和非线性关系)的过滤方法。

和F检验相似,它既可以做回归也可以做分类,并且包含两个类mutual_info_classif(互信息分类)和mutual_info_regression(互信息回归)。

这两个类的用法和参数都和F检验一模一样,不过互信息法比F检验更加强大,F检验只能够找出线性关系,而互信息法可以找出任意关系。

  1. from sklearn.feature_selection import mutual_info_classif as MIC
  2. result = MIC(x,y)

样本不均衡

通过观察,正负样本比例为 836:4899,属于样本不均衡范畴,可采用上采样的SMOTE算法对其进行样本不均衡处理。

  1. from imblearn.over_sampling import SMOTE
  2. over_samples = SMOTE(random_state=111)
  3. over_samples_x, over_samples_y = over_samples.fit_sample(x,y)

模型建立与调参

文章一开始已经提到过了,可选模型较多,这里举例三种模型逻辑回归、决策树、随机森林模型,其余模型的选用,小伙伴们可以自己动手练习练习。

二分类模型——逻辑回归模型

互信息与正则化对模型效果的影响

用学习曲线对参数C进行调整,分别在两个模型中进行调参。

超参数C : 一般不会超过1, 越大惩罚力度越小,本次选取从 0.05 - 2范围。

  1. from sklearn.linear_model import LogisticRegression as LR
  2. from sklearn.model_selection import cross_val_score as cvs
  3. lrl1 = LR(penalty='l1', solver='liblinear'
  4.           C=i, max_iter=1000, random_state=0)
  5. lrl2 = LR(penalty='l2', solver='liblinear'
  6.           C=i, max_iter=1000, random_state=0)
4ac22ad8933df7b62423ffcfb600014b.png

由图可知,在经过互信息过滤后,逻辑回归模型得分明显提高,且当超参数C=0.6时,模型效果是最好的。

包装法筛选变量

以逻辑回归为基分类器,结合包装法筛选变量,并运用交叉验证绘制学习曲线,探索最佳变量个数。

同时,运用SMOTE算法进行样本均衡处理,并比较均衡前后模型效果的变化。

  1. from sklearn.feature_selection import RFE
  2. LR_1 = LogisticRegression(penalty='l1', solver='liblinear'
  3.                           C=0.6, max_iter=1000, random_state=0)
  4. selector1 = RFE(LR_1, n_features_to_select=i, step=1)
  5. X_wrapper1 = selector1.fit_transform(x, y)
  6. once1=cvs(LR_1, X_wrapper1, y, cv=5, scoring='f1').mean()
bce3e6b712d5ac71f4c75beb42e38636.png

由图可见,样本均衡前后模型效果有大幅度增长。且两种正则化方法相差无几。

树模型——决策树

因为样本均衡化处理前后,对模型效果提升较为明显,因此在使用决策树模型建立之前,对样本进行均衡化处理。

因为深度参数max_depth是对决策树模型影响最大的参数之一,因此本案例正对决策树深度绘制学习曲线,探索决策树最佳参数。

  1. plt.plot(L_CVS, 'r')  # 交叉验证
  2. plt.plot(L_train, 'g')# 训练集
  3. plt.plot(L_test, 'b') # 测试集
b6c0d82a0efb1ae1ebde994385769238.png

由学习曲线可知,在max_depth=5时训练集和测试集模型效果均达到了最佳状态,当在max_depth大于5后,模型在训练集上的分数依然在上升,而测试集上的表现有所下降,这就是模型过拟合现象,因此最终我们选用max_depth=5

特征重要性

  1. features_imp = pd.Series(dtc.feature_importances_, 
  2.           index = x.columns).sort_values(ascending=False)
  3. features_imp
  1. 上期还款差额标签 0.705916
  2. 性别 0.101779
  3. 平均支出 0.064218
  4. 平均工资收入 0.047644
  5. 浏览行为数据 0.044333
  6. 教育程度 0.015257
  7. 婚姻状态 0.012665
  8. 本期账单最低还款额 0.004455
  9. 消费笔数 0.003734
  10. 本期账单余额 0.000000
  11. 信用卡额度 0.000000
  12. dtype: float64

决策树可视化

这里提出一点,如果需要深入理解决策树决策过程,可以借助决策树可视化来辅助理解。

  1. import graphviz
  2. from sklearn import tree
  3. #首先配置
  4. dot_data = tree.export_graphviz(dtc 
  5.       # 要对已经建成的dct这个实例化好的模型进行画图
  6.       ,feature_names= x.columns 
  7.       # 更改列名为中文
  8.       # ,class_names=[] 
  9.       # 更改标签名字
  10.       ,filled=True 
  11.       # 给每一个节点分配颜色,颜色约深表示叶子的纯度越高
  12.       ,rounded=True
  13.       # 节点性状为圆角
  14.       )
  15. graph = graphviz.Source(dot_data)
  16. graph

树模型——随机森林

  1. from sklearn.ensemble import RandomForestClassifier as RFC
  2. from sklearn.model_selection import GridSearchCV
  3. rfc = RFC(n_estimators=i+1,
  4.           n_jobs=-1,
  5.           random_state=90)
  6. score = cvs(rfc,over_samples_x_train, 
  7.             over_samples_y_train,
  8.             cv=5, scoring='f1').mean()

模型调参

有⼀些参数是没有参照的,一开始很难确定⼀个范围,这种情况下采用先通过学习曲线确定参数大致范围,再通过网格搜索确定最佳参数。

比如确定n_estimators范围时,通过学习曲线观察n_estimators在什么取值开始变得平稳,是否⼀直推动模型整体准确率的上升等信息。

9f24c74434eca5b8d10fdb919fc2c56b.png

对于其他参数也是按照同样的思路,如影响单棵决策树模型的参数max_depth来说,⼀般根据数据的⼤⼩来进⾏⼀个试探,比如乳腺癌数据很⼩,所以可以采⽤1~10,或者1~20这样的试探。

但对于像digit recognition那样的⼤型数据来说,我们应该尝试30~50层深度(或许还不⾜够),此时更应该画出学习曲线,来观察深度对模型的影响。

确定范围后,就可以通过网格搜索的方式确定最佳参数。其他参数就不一一举例了,大家可以动手尝试一下。

  1. # 调整max_depth
  2. param_grid = {'max_depth':np.arange(1201)}
  3. rfc = RFC(n_estimators=150,random_state=90, n_jobs=-1)
  4. GS = GridSearchCV(rfc,param_grid,cv=5, scoring='f1')
  5. GS.fit(over_samples_x, over_samples_y)
  6. GS.best_params_
  7. GS.best_score_

模型评价

本次案例模型评估使用classification_report

sklearn中的classification_report函数用于显示主要分类指标的文本报告.在报告中显示每个类的精确度,召回率,F1值等信息。

主要参数:
y_true:1维数组,或标签指示器数组/稀疏矩阵,目标值。
y_pred:1维数组,或标签指示器数组/稀疏矩阵,分类器返回的估计值。
labels:array,shape = [n_labels],报表中包含的标签索引的可选列表。
target_names:字符串列表,与标签匹配的可选显示名称(相同顺序)。
sample_weight:类似于shape = [n_samples]的数组,可选项,样本权重。
digits:int,输出浮点值的位数。

决策树验证集评价结果

最后这里举了一个决策树模型效果评价的例子,其余分类型模型评价同样可以使用。当然,模型评价方法不止这一种,大家也可以尝试着从其他角度来做模型评价。

  1. precision recall f1-score support
  2. 0 0.70 0.74 0.72 1454
  3. 1 0.72 0.68 0.70 1454
  4. accuracy 0.71 2908
  5. macro avg 0.71 0.71 0.71 2908
  6. weighted avg 0.71 0.71 0.71 2908

本文旨在梳理数据挖掘的一般过程,没有涉及到很复杂的算法,每个环节,如数据预处理、特征工程、模型建立于评价,均是常用的方法。

-- end --

 
 
 
 

28144d28f0c8f9e9f7ee9d0585c84090.jpeg

 
 
 
 
 
 
 
 
  1. 往期精彩回顾
  2. 适合初学者入门人工智能的路线及资料下载(图文+视频)机器学习入门系列下载机器学习及深度学习笔记等资料打印《统计学习方法》的代码复现专辑
  • 交流群

欢迎加入机器学习爱好者微信群一起和同行交流,目前有机器学习交流群、博士群、博士申报交流、CV、NLP等微信群,请扫描下面的微信号加群,备注:”昵称-学校/公司-研究方向“,例如:”张小明-浙大-CV“。请按照格式备注,否则不予通过。添加成功后会根据研究方向邀请进入相关微信群。请勿在群内发送广告,否则会请出群,谢谢理解~(也可以加入机器学习交流qq群772479961)

b836c18eeabead08298108c81a90452e.png

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/157722
推荐阅读
  

闽ICP备14008679号