Lending Club申请评分卡模型开发(Python)
一、文章解析
文章重点分为下列几个阶段
- 目标变量定义(好坏定义,以及灰色客户的定义)
- 样本概述和说明
- 部分数据字典
- 缺失值处理
- 筛选变量(基于IV值和皮尔森相关系数的多重共线性检测)
- 变量分箱(基于k-Means聚类算法的变量离散化)
- 模型训练
- 模型评估
二、评分卡开发目的
评分卡开发流程
三、数据准备
- 数据下载地址:
https://www.lendingclub.com/info/download-data.actionwww.lendingclub.com
- 开发样本与验证样本选择
在保证建模数据量的前提下,建模样本尽量选择距离当前时间较近的可用数据。因为如果距离当前时间较长的话,客户群体可能发生变化,社会环境、市场也有可能发生变化。缩短模型迭代周期。
- 开发样本期间:2017年第1、2季度(1月~6月)的数据
- 验证样本区间:2017年第3季度(7月~9月)
我们下载数据的时间是2018年5月,那么我们开发的样本到目前为止还款全部超过9个月。验证样本在未来2个月也会全部全部还款到9个月。
本次开发样本总共有204185条数据;验证样本数据有101018条数据,所以我们的数据量还是比较大的。
四、数据预处理
1、初始变量展示
原始变量145个,删除缺失比例高达92%以上的变量后,剩余107后变量。
删除缺失比例高达92%以上的变量后的数据字典展示
2、删除贷后变量,防止提前泄露模型信息
需删除的14个贷后变量
删除14个贷后变量后,目前剩余93个变量。
3、缺失值处理
94个变量的缺失情况(比例)展示
In[16]: #按缺失值比例从大到小排列
data.isnull().sum(axis=0).sort_values(ascending=False)/float(len(data))
Out[16]:
mths_since_last_record 0.820679
mths_since_recent_bc_dlq 0.758887
mths_since_last_major_derog 0.724567
mths_since_recent_revol_delinq 0.649809
mths_since_last_delinq 0.485901
il_util 0.132940
mths_since_recent_inq 0.114380
emp_title 0.069203
num_tl_120dpd_2m 0.047488
mths_since_rcnt_il 0.027072
mo_sin_old_il_acct 0.027072
bc_util 0.012387
percent_bc_gt_75 0.011947
bc_open_to_buy 0.011928
mths_since_recent_bc 0.011319
dti 0.000936
revol_util 0.000816
all_util 0.000129
... ...
mo_sin_old_rev_tl_op 0.000037
mo_sin_rcnt_rev_tl_op 0.000037
loan_amnt 0.000037
dtype: float64
常用的缺失值处理方法:
1)删除法
2)填充法(均值填充、拉格朗日填充、常数填充...)
关于缺失值的处理,我们分以下2种情况:
1)通过观察我们可以发现,前7个变量的缺失比例均在10%以上。针对缺失值比例10%的以上的变量,我们结合实际业务变量含义,对缺失比例较大的前7个变量的缺失值进行处理999填充处理或者均值填充处理。
# 缺失比例较大的前7个变量的缺失值处理
values = {'mths_since_last_record': 999, 'mths_since_last_major_derog': 999, 'mths_since_recent_bc_dlq': 999, 'mths_since_recent_inq': 999,
'mths_since_last_delinq':999,'mths_since_recent_revol_delinq':999,'il_util':data['il_util'].mean()
}
data.fillna(value=values,inplace = True)
2)针对缺失比例低于10%的变量,考虑到我们建模数据量还是比较大的,我们采取直接删除含任意缺失值的记录。
- 删除含任意缺失值的记录后,我们的数据量从32.5万条变为27.8万条,删除了约5万条含缺失值的记录。
4)数据清洗-异常值处理
本次异常值的处理主要针对数据不规范、不干净的变量进行清洗。列举以下几点:
- 删除特征变量值结尾多余的字符,比如'year','years','%',' ','months','xx'等;
def del_str_process(data):
data['term'] = data['term'].str.replace('months',' ').str.strip().astype('float64')
data['int_rate'] = data['int_rate'].str.replace('%',' ').str.strip().astype('float64')
data['emp_length'] = data['emp_length'].str.replace('< 1 year','0').str.replace('10+ years','11').str.replace('n/a','-1').str.strip()
data['emp_length'] = data['emp_length'].str.replace('years',' ').str.replace('year',' ').str.strip()
data['emp_length'][data['emp_length'] == '10+'] = 11
data['emp_length'] = data['emp_length'].astype('float64')
data['revol_util'] = data['revol_util'].str.replace('%',' ').str.strip().astype('float64')
# 以下四个字段均为字符型变量转化为数值型变量
data['delinq_2yrs'] = data['delinq_2yrs'].astype('float64') # 字段解释:借款人信用档案过去2年内30天以上逾期还款次数(本来就是数值型)
data['annual_inc'] = data['annual_inc'].astype('float64') # 未核实的年收入(本来就是数值型)
data['revol_bal'] = data['revol_bal'].astype('float64') # 总信贷周转余额
data['total_acc'] = data['total_acc'].astype('float64') # 借款人当前信用额度
return data
loandata = del_str_process(loandata)
- 对部分字符型变量进行数字编码以及对部分二值型字符变量进行0-1编码;
# 字符型变量进行编码
def char_encoding_process(data):
data['grade'].replace(['A','B','C','E','F','D','G'],[1,2,3,4,5,6,7],inplace = True)
data['home_ownership'].replace(['OWN', 'MORTGAGE','RENT', 'OTHER', 'NONE', 'ANY'],[4,3,2,1,0,5],inplace = True)
return data
loandata = char_encoding_process(loandata)
5)删除以下部分对建模无意义的变量
# 删除变量的中文释义如下:
# earliest_cr_line 借款人最早报出授信额度的月份
# zip_code 邮政编码前3位
# addr_state 州、省份(地址信息)
# policy_code 通过unique()发现变量只有一个值1(取值1.0,1,属数据的不规范),对模型无区分度
# title 购买商品名称,与purpose字段取值重合,故可删除该字段,保留变量purpose即可
# sub_grade 风险等级细分,与字段grade取值重合,故可删除该字段,保留变量grade即可
# emp_title 工作职位,分类变量,unique取值过多(88529),直接删除
至此,剩余86个建模变量。
五、目标变量:好坏客户定义
- 根据行业以及之前各产品的业务经验,正常还款9期或者12期以上的借款人,在9期或者12期以后的逾期率会趋于稳定,我们以此作为表现期。
- 我们用来定义好坏,我们定义逾期30天以上的客户为坏客户。
- 灰色客户定义:
实际工作中,我们会结合vintage账龄分析,以及逾期迁移率分析来对好坏客户进行定义。
loandata['loan_status'].replace(['Fully Paid', 'Charged Off','Current','Late (31-120 days)','Late (16-30 days)','In Grace Period','Default'] ,
[0,1,0,1,2,2,2],inplace = True)
六、初始建模样本概述
完成以上多步的数据清洗的预处理工作后,确保数据干净,且符合逻辑回归模型对数据格式的要求,我们基本确认我们最终的建模样本。
初始建模样本
可以观测到:
开发样本约17万条,坏客户占比5.1%,属于不平衡样本,后续建模需做不平衡样本处理。
验证样本约10万条,坏客户占比2.6%。
接下来进行变量分箱以及WOE转换。
七、基于k-means算法的变量分箱
有别于评分卡的经典分箱方式(等深分箱、等段分箱、卡方最优分箱),本次我们分箱我们尝试采用机器学习的方法对变量进行分箱离散化。
连续变量,离散有序变量分箱方式:K-means算法.
离散无序变量:决策树分箱,或者one-hot编码.
- 变量初步分箱结果
变量分箱结果(部分展示)
- 手动调箱
1)删除变量取值只有2个,且变量分箱结果好客户占比0%,或好客户占比100%的变量
2)合并分箱结果不合理的箱(比如该箱坏客户占比0%,将该分箱与相邻分箱合并)
八、基于IV值的变量筛选
In[62]:bin_iv['var_name'][bin_iv['iv'] >= 0.02].unique()
Out[62]:
array(['acc_open_past_24mths_bin', 'all_util_bin', 'avg_cur_bal_bin',
'bc_open_to_buy_bin', 'bc_util_bin', 'dti_bin', 'funded_amnt_bin',
'funded_amnt_inv_bin', 'grade_bin', 'home_ownership_bin',
'il_util_bin', 'inq_fi_bin', 'inq_last_12m_bin',
'inq_last_6mths_bin', 'installment_bin', 'int_rate_bin',
'loan_amnt_bin', 'mo_sin_old_rev_tl_op_bin',
'mo_sin_rcnt_rev_tl_op_bin', 'mo_sin_rcnt_tl_bin', 'mort_acc_bin',
'mths_since_rcnt_il_bin', 'mths_since_recent_bc_bin',
'mths_since_recent_inq_bin', 'num_tl_op_past_12m_bin',
'open_acc_6m_bin', 'open_il_12m_bin', 'open_il_24m_bin',
'open_rv_12m_bin', 'open_rv_24m_bin', 'percent_bc_gt_75_bin',
'revol_util_bin', 'tot_hi_cred_lim_bin', 'total_bc_limit_bin',
'verification_status_bin'], dtype=object)
可以观测到,IV值≥0.02的变量,目前有35个。
九、WOE映射
对iv值≥0.02的35个变量进行woe转换.
# 自定义分箱映射函数
def _applyBinMap(x, bin_map):
bin_res = np.array([0] * x.shape[-1], dtype=int)
for i in bin_map.index:
upper = bin_map['upper'][i]
lower = bin_map['lower'][i]
x1 = x[np.where((x > lower) & (x <= upper))[0]]
mask = np.in1d(x, x1)
bin_res[mask] = i
bin_res = pd.Series(bin_res, index=x.index)
bin_res.name = x.name + '_bin'
return bin_res
分箱及woe映射.
woe_exchange = pd.DataFrame()
for colus in data_woe_mapss.columns:
x = data_woe_mapss[colus]
woe_map = bin_handle[bin_handle['var_name'] == colus + '_bin']
woe_map.set_index('bin',inplace = True)
woe_res = _applyBinMap(x,woe_map) # 分箱映射函数
woe_res = woe_res.map(woe_map['woe']) # WOE映射!!!!
woe_res.name = colus + '_woe'
woe_exchange = pd.concat([woe_exchange,woe_res],axis=1)
十、基于皮尔森相关系数的多重共线性检测
我们对35个变量进行皮尔森相关系数分析,得到以下皮尔森相关系数图谱。
皮尔森相关系数检测图谱
我们选择出皮尔森相关系数阈值0.6以上的两两相关变量,并结合变量的IV值,删除其中IV值低的变量。最后得到以下14个IV相关较高,且变量间多重共线性较低的变量。
十一、训练数据、测试数据分割
# 训练数据、测试数据进行切分
from sklearn.model_selection import train_test_split
X_train, X_test, Y_train, Y_test = train_test_split(x_data,y_data,test_size=0.25)
十二、模型训练、迭代及最优模型选择
# 构建分类器进行训练,并初始化分类器
from sklearn.linear_model import LogisticRegression as LR
lr = LR(class_weight='balanced') # 构建逻辑回归分类器
LR_model = lr.fit(X_train,Y_train) # 模型训练
十三、模型评估
0、混淆矩阵
1、ROC曲线
ROC曲线
AUC = 0.72
2、KS曲线
K-S曲线(ks_value = 0.321)
模型KS值 = 0.32
3、PSI计算
十四、标准评分卡生成
- 最终生成的评分卡分数(cards_score)
生成评分卡分数
十五、本次评分卡开发总结
①、145个初选建模变量数据字段中文解释、业务含义熟悉(40%)
②、数据清洗、建模变量筛选(删除贷后变量,iv值、共线性检测删除变量,达到筛选变量的目的)(30%)
③、模型训练(10%)
④、模型评估(20%)