在前面的文章中介绍了风控评分卡及模型的原理,本篇使用bbbrisk来实现评分卡,来帮助大家理解评分卡建模的流程。
数据处理
bbbrisk是python的一个风控包,目前提供的功能主要是构建评分卡,里面包含构建评分卡的相关功能和原始数据
首先安装这个包:pip install bbbrisk
bbbrisk依赖于numpy、pandas和sklearn包,最好提前安装好上述包
首先导入需要的数据,并查看数据结构
# 加载数据pd.set_option('display.float_format',lambdax:'%.2f'%x)# 设置输出2位小数,防止出现科学计数法不直观data=br.datasets.load_bloan()data.head()data.describe()从输出的数据来看,bbbrisk自带的小贷数据共包含10个变量与客户好坏标签
数据共2万条,其中income这个字段的缺失值比较多
接着看一下特征之间的相关性
figure,ax=plt.subplots(figsize=(15,15))sns.heatmap(data.corr(),square=True,annot=True)
可以看出due60和due90这两个特征相关性很高,后续可以考虑只保留一个。
数据分箱
这里我们直接使用bbbrisk进行自动分箱,做一个基本的数据分箱并查看结果
x=data.iloc[:,:-1]# 变量数据y=data['is_bad']# 自动分箱bin_sets=br.bins.batch.autoBins(x,y,enum_var=['city','marital'])# 自动分箱,如果有枚举变量,必须指出哪些是枚举变量bin_stats=br.bins.batch.bin_stats(x,y,bin_sets)# 统计各个变量的分箱情况br.display.pd.set(width=300,max_colwidth=30,max_rows=30)# 美化pandas的显示方式forvarinbin_stats:# 逐个变量打印分箱结果print('\n变量'+var+'的分箱结果:\n',bin_stats[var])# 打印当前变量的分箱统计结果代码会给出每个特征对应的分箱结果和对应的IV值和Badrate,这里给出几个特征的结果美化一下:
细看一下自动分箱后的结果的问题还是挺多的,例如age字段,有两个箱体IV值不符合要求,同时从badrate看也不单调,同样的变量loan_num,变量debrat等等也都有这种问题,所以自动分箱的结果可以考虑IV值和Badrate单调性符合要求的分箱结果,其他不符合要求的可以接着通过之前文章所说的其他分箱方法尝试再次分箱。
这里直接给出最后的分箱结果,帮助大家先了解相关流程。
这里也是直接使用bbrisk的功能实现分箱。在bbbrisk中,约定每个变量的分箱都以list来表示,list中第i个元素代表第i个分箱
简单来说,主要就三种情况:
- 如果是范围分箱,就用[a,b]格式
它遵循左开右闭,即它实际代表的范围是(a,b],如果要左闭,就把a取小一点 - 如果是枚举值就直接填上枚举值a
- 如果要合并,就用小括号()括起来,例如([a,b],[c,d],e)
# 变量的分箱bin_sets={'rev':[[0,0.1],(['-',0],[0.1,0.37]),[0.37,0.64],([0.64,1.2],[2,'+']),[1.2,2],],'age':[[80,'+'],[60,80],[45,60],['-',45]],'city':[('J','E','I'),'_other',('D','N','S'),('F','P')],'income':[[1000,5000],[5000,9000],(['-',1000],[20000,'+'],None),[9000,16000],[16000,20000]],'marital':[1,0,2],'debrate':[([0,0.1],[850,'+']),([0.1,0.5],[5,850]),([0.5,0.8],0),[0.8,5]],'due30':[0,1,2,(3,4),[4,'+']],'due60':[0,1,2,[2,'+']],'due90':[0,1,[1,'+']],'loan_num':[[3,'+'],(2,3),1,0]}bin_stats=br.bins.batch.bin_stats(x,y,bin_sets)# 统计各个变量的分箱情况br.display.pd.set(width=300,max_colwidth=30,max_rows=30)# 美化pandas的显示方式forvarinbin_stats:# 逐个变量打印分箱结果print('\n变量'+var+'的分箱结果:\n',bin_stats[var])# 打印当前变量的分箱统计结果从输出的最终的结果看badrate都有非常明显的趋势,它们都是有效的可以作为入模变量。
建模与评估
构建模型,并使用逐步回归来删选最终的变量
# 构建评分卡model,card=br.model.scoreCard(x,y,bin_sets,train_param={'random_state':0})# 构建评分卡,为了使结果能重现,笔者设置了固定的随机种子score=card.predict(x[card.var])# 用评分卡进行评分card.featureScore# 评分卡-特征得分表card.baseScore# 打印结果print('\n-----【 模型性能评估 】----')print('* 模型训练AUC:',model.train_auc)# 打印模型训练数据集的AUCprint('* 模型测试AUC:',model.test_auc)# 打印模型测试数据集的AUCprint('* 模型训练KS:',model.train_ks)# 打印模型训练数据集的KSprint('* 模型测试KS:',model.test_ks)# 打印模型测试数据集的KSprint('\n--------【 模型 】---------')print('* 模型使用的变量:',model.var)# 模型最终使用的变量print('* 模型权重:',model.w)# 模型的变量权重print('* 模型阈值:',model.b)
从输出的结果看模型的AUC大于0.8,整体效果不错
# 计算阈值表与分数分布图thd_tb=br.report.get_threshold_tb(score,y,bin_step=10)# 阈值表thd_tbbr.report.draw_score_disb(score,y,bin_step=10,figsize=(20,8))
从分数分布图可看出,分数越低,坏客户的占比越高,当分数⩾790时,基本坏客户的占比就较少了,同时,从分布图还可以看出,整体客户质量是较好的,分数基本集中在高分段,高分段只有个别客户坏账,这可以理解为意外情况导致的逾期。(备注:在实践中,分数分布图一般呈现为正态分布或二八分布,在本例中就是二八分布。
https://www.bbbdata.com/scorecard/card
https://geekdaxue.co/read/yingtaoxiang@hello/cil23y