Lending Club申请评分卡模型开发(Python)

Lending Club申请评分卡模型开发(Python)

一、文章解析

文章重点分为下列几个阶段

  • 目标变量定义(好坏定义,以及灰色客户的定义)
  • 样本概述和说明
  • 部分数据字典
  • 缺失值处理
  • 筛选变量(基于IV值和皮尔森相关系数的多重共线性检测)
  • 变量分箱(基于k-Means聚类算法的变量离散化)
  • 模型训练
  • 模型评估

二、评分卡开发目的

评分卡开发流程

三、数据准备

  • 数据下载地址:

https://www.lendingclub.com/info/download-data.action​www.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%)

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值