[B8]信用评分卡建模

本次做的是一个银行信用评分卡项目,主要就是通过对银行的客户进行区分,根据信用等级划分为“好客户”和“坏客户”两个类别,然后利用机器学习算法进行建模分析,最后建立信用评分卡,为银行做出放贷决策提供依据。

  • 数据预处理

第一步:导入数据

#导入科学计算包
import numpy as np
import matplotlib as mlt
import matplotlib.pyplot as plt
plt.rc('font', family='Microsoft YaHei')
%matplotlib inline
import seaborn as sns
import pandas as pd
import os
os.chdir("/Jupyter_working_path/Numpy/data")
df = pd.read_csv(r"cs-training.csv")
df

在这里插入图片描述
可以看出,该数据集一共有15万行,12个字段。但是由于英文表示的字段名太长,所以改用中文

df0 = df.rename(columns={"Unnamed:0":"ID",
       "SeriousDlqin2yrs":"好坏客户",
       "RevolvingUtilizationOfUnsecuredLines":"额度比值",
       "age":"年龄",
       "NumberOfTime30-59DaysPastDueNotWorse":"逾30-59天",
       "DebtRatio":"负债率",
       "MonthlyIncome":"月收入",
       "NumberOfOpenCreditLinesAndLoans":"信贷数",
       "NumberOfTimes90DaysLate":"逾90天",
       "NumberRealEstateLoansOrLines":"固定资产",
       "NumberOfTime60-89DaysPastDueNotWorse":"逾60-89天",
       "NumberOfDependents":"家属"})
df0.head(5)

在这里插入图片描述

第二步:数据清洗

  • 处理缺失值
#查看缺失值
df0.info()

在这里插入图片描述

可以看出“月收入”和“家属”两个字段有缺失值,我把它们找出来

def missing_values_table(df0):
    #全部缺失值
    mis_val=df0.isnull().sum()
    #缺失值比例
    mis_val_percent=100*df0.isnull().sum() /len(df0)
    #做成一个表
    mis_val_table=pd.concat([mis_val,mis_val_percent], axis=1)
    #改列名
    mis_val_table_ren_columns = mis_val_table.rename(columns={0:'缺失值',1:'缺失比例'})
    #对缺失值排序
    mis_val_table_ren_columns = mis_val_table_ren_columns[mis_val_table_ren_columns.iloc[:,1] != 0].sort_values('缺失比例',ascending=False).round(1)
    
    #打印表
    print("数据有"+str(df0.shape[1])+"列.\n"  "其中" + str(mis_val_table_ren_columns.shape[0]) +"列含有缺失值")
    
    #返回缺失行列
    return mis_val_table_ren_columns

missing_values_table(df0)

在这里插入图片描述
对于缺失值的处理可以有一下几种方法:
df = df.dropna() #去掉缺失的行
df = df.fillna(num) #补充固定的数
df = df.fillna(df.mean()) #补充均值
df = df.fillna(df.median()) #补充中位数
df = df.interpolate()#插值法

#月收入的缺失值有点多,可以考虑用中位数填补
df0['月收入'].fillna(df0['月收入'].median(),inplace=True)

在这里插入图片描述

  • 异常值的处理

可以采用分享发,将客户年龄进行分箱,观察异常值所在区间

#分箱法
df0['年龄'].hist(bins=50)
plt.savefig("C:\\Jupyter_working_path\\Numpy\\picture")

在这里插入图片描述

def blk(floor, root):
    def f(x):
        if x <floor:
            x=floor
        elif x >root:
            x = root
        return x
    return f


q1= df0['年龄'].quantile(0.01)
q99 = df0['年龄'].quantile(0.99)
blk_tot=blk(floor=q1,root=q99)

df0['年龄'] = df0['年龄'].map(blk_tot)
df0['年龄'].hist(bins=50)
plt.savefig("C:\\Jupyter_working_path\\Numpy\\picture0")

在这里插入图片描述
第三步:探索性分析

  • 单变量分析

分析好坏客户比

#单变量:
age_cut = pd.cut(df0['年龄'],5)
age_cut_grouped=df0["好坏客户"].groupby(age_cut).count()
age_cut_grouped1=df0["好坏客户"].groupby(age_cut).sum()

df1=pd.merge(pd.DataFrame(age_cut_grouped), pd.DataFrame(age_cut_grouped1),right_index=True,left_index=True)
df1.rename(columns={"好坏客户_x":"好客户","好坏客户_y":"坏客户"},inplace=True)
df1.insert(2,"坏客户率",df1["坏客户"]/df1["好客户"])

ax1 = df1[["好客户","坏客户"]].plot.bar()
ax1.set_xticklabels(df1.index,rotation=15)
ax1.set_ylabel("客户数")
ax1.set_title("年龄于好坏客户分布图")
plt.savefig("C:\\Jupyter_working_path\\Numpy\\picture1")

在这里插入图片描述
可见坏客户主要集中在23-60岁,可能是60岁以上的客户对于接待会更加谨慎,担心还不上款,所以借贷也相对减少

ax11 = df1["坏客户率"].plot()
ax11.set_ylabel("坏客户率")
ax11.set_title("坏客户率随年龄变化趋势图")
plt.savefig("C:\\Jupyter_working_path\\Numpy\\picture2")

在这里插入图片描述
可见,坏客户率会随着年龄而逐渐降低

  • 多变量分析
#多变量:
plt.rcParams["font.sans-serif"] = 'SimHei'
plt.rcParams['axes.unicode_minus'] = False
corr = df0.corr() #计算各个变量的相关系数
xticks = list(corr.index) #x轴标签
yticks = list(corr.index)  #y轴标签
fig = plt.figure()
axl2 = fig.add_subplot(1,1,1)
sns.heatmap(corr, annot=True, cmap="rainbow", ax=axl2, linewidths=.5, annot_kws={'size':6,'weight':'bold','color':"blue"})

axl2.set_xticklabels(xticks, rotation=35, fontsize=9)
axl2.set_yticklabels(yticks, rotation=0, fontsize=9)
plt.savefig("C:\\Jupyter_working_path\\Numpy\\picture3")

在这里插入图片描述
第四步:WOE值替换和LR建模

  • 分箱
#分箱
pinf = float('inf') #正无穷
ninf = float('-inf') #负无穷
cut1=pd.qcut(df0["额度比值"],4, labels=False)
cut2=pd.qcut(df0["年龄"],8, labels=False)
bins3=[ninf,0,1,3,5,pinf]
cut3=pd.cut(df0["逾30-59天"],bins3,labels=False)
cut4=pd.qcut(df0["负债率"],3, labels=False)
cut5=pd.qcut(df0["月收入"],4, labels=False)
cut6=pd.qcut(df0["信贷数"],4, labels=False)
bins7=[ninf,0,1,3,5,pinf]
cut7=pd.cut(df0["逾90天"],bins7, labels=False)
bins8=[ninf,0,1,2,3,pinf]
cut8=pd.cut(df0["固定资产"],bins8, labels=False)
bins9=[ninf,0,1,3,pinf]
cut9=pd.cut(df0["逾60-89天"],bins9, labels=False)
bins10=[ninf,0,1,3,5,pinf]
cut10=pd.cut(df0["家属"],bins10, labels=False)
  • 计算WOE值 和 IV 值
#好坏客户比率
rate = df0["好坏客户"].sum()/(df0["好坏客户"].count() - df0["好坏客户"].sum())
#定义WOE计算函数
def get_woe_data(cut):
    grouped=df0["好坏客户"].groupby(cut, as_index = True).value_counts()
    woe=np.log(pd.DataFrame(grouped).unstack().iloc[:,1] / pd.DataFrame(grouped).unstack().iloc[:,0] /rate) 
    #计算每个分组的woe值
    return(woe)

cut1_woe=get_woe_data(cut1)
cut2_woe=get_woe_data(cut2)
cut3_woe=get_woe_data(cut3)
cut4_woe=get_woe_data(cut4)
cut5_woe=get_woe_data(cut5)
cut6_woe=get_woe_data(cut6)
cut7_woe=get_woe_data(cut7)
cut8_woe=get_woe_data(cut8)
cut9_woe=get_woe_data(cut9)
cut10_woe=get_woe_data(cut10)
  • 定义IV值计算函数
#定义IV值计算函数
def get_IV_data(cut, cut_woe):
    grouped=df0["好坏客户"].groupby(cut, as_index=True).value_counts()
    cut_IV=((pd.DataFrame(grouped).unstack().iloc[:,1]/df0["好坏客户"].sum() -pd.DataFrame(grouped).unstack().iloc[:,0] /(df0["好坏客户"].count() - df0["好坏客户"].sum()))* cut_woe).sum()
    return(cut_IV)

#计算各分组的IV值
cut1_IV=get_IV_data(cut1, cut1_woe)
cut2_IV=get_IV_data(cut2, cut2_woe)
cut3_IV=get_IV_data(cut3, cut3_woe)
cut4_IV=get_IV_data(cut4, cut4_woe)
cut5_IV=get_IV_data(cut5, cut5_woe)
cut6_IV=get_IV_data(cut6, cut6_woe)
cut7_IV=get_IV_data(cut7, cut7_woe)
cut8_IV=get_IV_data(cut8, cut8_woe)
cut9_IV=get_IV_data(cut9, cut9_woe)
cut10_IV=get_IV_data(cut10, cut10_woe)
  • 各组的IV值可视化
#各组的IV值可视化
df_IV=pd.DataFrame([cut1_IV,cut2_IV,cut3_IV,cut4_IV,cut5_IV,cut6_IV,cut7_IV,cut8_IV,cut9_IV,cut10_IV], index=df0.columns[2:])
df_IV.plot(kind="bar")
#for a,b in zip(range(10),df1.values):   报错TypeError: only size-1 arrays can be converted to Python scalars
    #plt.text(a,b,'%.2f' % b,ha='center', va='bottom',fontsize=9)
plt.savefig("C:\\Jupyter_working_path\\Numpy\\picture4")

在这里插入图片描述

df_new=df0.drop(["负债率","月收入","信贷数","固定资产","家属"],axis=1)

在这里插入图片描述

第五步:LR建模

#LR建模(逻辑斯蒂回归模型)
#替换数据
def replace_data(cut,cut_woe):
    a = []
    for i in cut.unique():
        a.append(i)
        a.sort()
    for m in range(len(a)):
        cut.replace(a[m],cut_woe.values[m], inplace=True)
    return cut

#进行替换
df_new["可用额度比值"]=replace_data(cut1, cut1_woe)
df_new["年龄"]=replace_data(cut2, cut2_woe)
df_new["逾30-59天"]=replace_data(cut3, cut3_woe)
df_new["逾90天"]=replace_data(cut7, cut7_woe)
df_new["逾60-89天"]=replace_data(cut9, cut9_woe)
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import roc_curve,auc

x = df_new.iloc[:,1:]
y = df_new.iloc[:,0]

x_train,x_test,y_train,y_test=train_test_split(x,y,test_size=0.4,random_state=0)

#模型训练
model=LogisticRegression()
clf=model.fit(x_train,y_train)
print("测试成绩:{}".format(clf.score(x_test,y_test)))
y_pred=clf.predict(x_test)
y_pred1=clf.decison_function(x_test)

在这里插入图片描述

  • 绘制ROC曲线以及计算AUC值
#绘制ROC曲线以及计算AUC值
fpr,tpr,threshold = roc_curve(y_test,y_pred1)
roc_auc = auc(fpr,tpr)
plt.plot(fpr,tpr,color='darkorange',
        label='ROC curve(area =%0.2f)' % roc_auc)
plt.plot([0,1],[0,1],color='navy',linestype='--')
plt.xlim([0.0,1.0])
plt.ylim([0.0,1.0])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('ROC_curve')
plt.legend(loc='lower right')
plt.show()

在这里插入图片描述

  • 将模型转化成信用分
    coe = model.coef_
import numpy as np
factor = 20/np.log(2)
offset = 600 - 20*np.log(20)/np.log(2)
  • 定义变量分数计算函数
def get_score(coe,woe,factor):
    scores=[]
    for w in woe:
        score = round(coe*w*factor,0)
        scores.append(score)
    return scores
  • 计算每个变量得分
x1 = get_score(coe[0][0],cut1_woe,factor)
x2 = get_score(coe[0][1],cut2_woe,factor)
x3 = get_score(coe[0][2],cut3_woe,factor)
x7 = get_score(coe[0][3],cut7_woe,factor)
x9 = get_score(coe[0][4],cut9_woe,factor)
  • 打印输出每个特征对应的分数
print("可用额度对应的分数:{}".format(x1))
print("年龄对应的分数:{}".format(x2))
print("逾期30-59天笔数对应的分数:{}".format(x3))
print("逾期90天笔数对应的分数:{}".format(x7))
print("逾期60-89天笔数对应的分数:{}".format(x9))

在这里插入图片描述
好了,大功告成,还有很多地方需要完善,继续加油!

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值