基于Python的信用评分卡建模分析

1.背景介绍

信用评分技术是一种应用统计模型,其作用是对贷款申请人(信用卡申请人)做风险评估分值的方法。信用评分卡模型是一种成熟的预测方法,尤其在信用风险评估以及金融风险控制领域更是得到了比较广泛的使用。信用评分卡可以根据客户提供的资料、客户的历史数据、第三方平台(芝麻分、京东、微信等)的数据,对客户的信用进行评估。信用评分卡的建立是以对大量数据的统计分析结果为基础,具有较高的准确性和可靠性。
本文通过对Kaggle上的 Give Me Some Credit (附:[Give me some cridets_百度网盘] 提取码: 1234)数据的挖掘分析,结合信用评分卡的建立原理,完成了数据处理、特征变量选择、变量WOE编码离散化、logistic回归模型开发评估、信用评分卡和自动评分系统创建等,为金融放款机构等的风险水平控制给予了参考。

在公众号「python风控模型」里回复关键字:学习资料

2.数据处理

2.1数据说明

数据来源于Kaggle的Give Me Some Credit竞赛项目,其中cs-training.csv文件有15万条的样本数据,包含了11个变量,大致情况如下表所示。
datadictionary

2.2 准备工作

用jupyter notebook处理数据,需要先做一些准备,需先把一些必要的数据分析包导入操作台。

# 读取数据
import numpy as np
import pandas as pd
data = pd.read_csv('data/cs-training.csv')
data = data.iloc[:,1:]
data.head()
123456
123456

输出:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LMpnARjl-1637058396047)(https://www.pianshen.com/images/410/7be17b73d739986a83681f97f86adb9a.png)]

  • 简单预览数据
# 数据大小
data.shape

(150000, 11)

# 数据整体预览
data.describe()

输出:
在这里插入图片描述

# 数据信息查看
data.info()

由结果可见,特征量MonthlyIncome缺失数量较多,为29731个;而NumberOfDependts缺失较少,数量为3924个。

2.3 数据预处理

2.3.1 缺失值处理

数据缺失情况在现实问题中非常普遍,这会导致一些不能处理缺失值的分析方法无法应用,因此,在信用风险评级模型开发的第一步就需要进行缺失值处理。缺失值处理的方法,包括如下几种:
(1) 直接删除含有缺失值的样本。
(2) 根据样本之间的相似性填补缺失值。
(3) 根据变量之间的相关关系填补缺失值。
变量MonthlyIncome缺失率比较大,所以我们根据变量之间的相关关系填补缺失值,采用随机森林法进行填补。

from sklearn.ensemble import RandomForestRegressor
def add_missing(df):
    process_df=df.ix[:,[5,0,1,2,3,4,6,7,8,9]]
    # 分成已知特征值和位置特征值两部分
    known=process_df[process_df['MonthlyIncome'].notnull()].as_matrix()
    unknown=process_df[process_df['MonthlyIncome'].isnull()].as_matrix()
    Y=known[:,0]
    X=known[:,1:]
    rfr=RandomForestRegressor(random_state=0, n_estimators=200,max_depth=3,n_jobs=-1)
    rfr.fit(X,Y)
    predicted=rfr.predict(unknown[:,1:])
    df.loc[df['MonthlyIncome'].isnull(),'MonthlyIncome']=predicted
    return df
data=add_missing(data)
1234567891011121314
1234567891011121314

NumberOfDependents变量缺失值比较少,可以直接删除,对总体模型不会造成太大影响。另外对缺失值处理完之后,删除重复项。

# 缺失值和重复值删除
data=data.dropna()
data=data.drop_duplicates()
123
123

2.3.2 异常值处理

缺失值处理完毕后,我们还需要进行异常值处理。异常值是指明显偏离大多数抽样数据的数值,比如个人客户的年龄大于100或小于0时,通常认为该值为异常值。找出样本总体中的异常值,通常采用离群值检测的方法。 离群值检测的方法有单变量离群值检测、局部离群值因子检测、基于聚类方法的离群值检测等方法。

在本数据集中,采用单变量离群值检测来判断异常值,采用箱线图。

对于age变量而言,我们认为大于100岁小于等于0岁的为异常值,由箱线图可知,异常值样本不多,故直接删除

# 选出 3,7,9做箱线图,选出年龄来做图观察
import matplotlib.pyplot as plt#导入图像库
%matplotlib inline
data_box = data.iloc[:,[3,7,9]]
data_box.boxplot()
12345
12345

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-p2LetEX8-1637058396054)(https://www.pianshen.com/images/946/e93cac48b6a897e0dc171a31d7ba7e72.png)]

dataage=data[['age']]
dataage.boxplot()
12
12

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FOgGNCpk-1637058396055)(https://www.pianshen.com/images/399/d5c3a5e24cd9fe875780d659bf523e87.png)]
由上面的两张图发现变量age中存在0,显然是异常值。变量NumberOfTime30-59DaysPastDueNotWorse、NumberOfTimes90DaysLate、NumberOfTime60-89DaysPastDueNotWorse这三个变量,均存在异常值,90多,两个,且剔除其中一个变量的96、98值,其他变量的也会相应被剔除。

数据集中好客户为0,违约客户为1,考虑到正常的理解,能正常履约并支付利息的客户为1,取反。

# 剔除异常值
data=data[data['age']>0]
data=data[data['NumberOfTimes90DaysLate']<90]
# 变量SeriousDlqin2yrs取反
data['SeriousDlqin2yrs']=1-data['SeriousDlqin2yrs']
12345
12345

2.3.3 数据切分

为了验证模型的拟合效果,我们需要对数据集进行切分,分成训练集和测试集。

from sklearn.cross_validation import train_test_split
Y=data['SeriousDlqin2yrs']
X=data.ix[:,1:]

X_train,X_test,Y_train,Y_test=train_test_split(X,Y,test_size=0.3,random_state=0)

train=pd.concat([Y_train,X_train],axis=1)
test=pd.concat([Y_test,X_test],axis=1)

train.to_csv('data/TrainData.csv',index=False )
test.to_csv('data/TestData.csv',index=False )
1234567891011
1234567891011

2.3.4 单变量探索性分析

在建立模型之前,我们一般会对现有的数据进行 探索性数据分析(Exploratory Data Analysis) 。 EDA是指对已有的数据(特别是调查或观察得来的原始数据)在尽量少的先验假定下进行探索。常用的探索性数据分析方法有:直方图、散点图和箱线图等。例如,我们对特征量年龄和月收入进行分析,如下。

# 对x2 值进行探索分析
import seaborn as sns
age = data['age']
sns.distplot(age)
1234
1234

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Zan2zVDR-1637058396056)(https://www.pianshen.com/images/851/2c767d742b1ec110dc315a7054b91753.png)]
可以看到,年龄的分布大致呈正态分布,符合统计分析假设。

# 对MonthlyIncome 进行分析,为了使图形更直观,将x轴范围设置在50000以内
mi = data[data['MonthlyIncome']<50000]['MonthlyIncome']
sns.distplot(mi)
123
123

月收入的分布大致呈正态分布,符合统计分析假设。

3 变量选择

特征变量选择(排序)对于数据分析、机器学习从业者来说非常重要。好的特征选择能够提升模型的性能,更能帮助我们理解数据的特点、底层结构,这对进一步改善模型、算法都有着重要作用。 在本文中,我们采用信用评分模型的变量选择方法,通过WOE分析方法,即通过比较指标分箱和对应分箱的违约概率来确定指标是否符合经济意义。首先我们对变量进行离散化(分箱)处理。

3.1 变量分箱处理

又叫连续变量离散化,信用评分卡开发中一般有常用的等距分段、等深分段、最优分段。首先选择对连续变量进行最优分段,在连续变量的分布不满足最优分段的要求时,再考虑对连续变量进行等距分段。最优分箱的代码如下:

import scipy.stats as stats
def mono_bin(Y,X,n):
    good=Y.sum()
    bad=Y.count()-good
    r=0
    while np.abs(r)<1:
        d1=pd.DataFrame({'X':X,'Y':Y,'Bucket':pd.qcut(X,n)})
        d2=d1.groupby(['Bucket'])
        r,p=stats.spearmanr(d2['X'].mean(),d2['Y'].mean())
        n=n-1
#同时得到了某个d2和n
    print(r,n)
    d3=pd.DataFrame(d2['X'].min(),columns=['min'])
    d3['min']=d2['X'].min()
    d3['max']=d2['X'].max()
    d3['sum']=d2['Y'].sum()
    d3['total']=d2['Y'].count()
    d3['rate']=d2['Y'].mean()
    d3['goodattribute']=d3['sum']/good
    d3['badattribute']=(d3['total']-d3['sum'])/bad
    d3['woe']=np.log(d3['goodattribute']/d3['badattribute'])
    iv=((d3['goodattribute']-d3['badattribute'])*d3['woe']).sum()
    d4=d3.sort_index(by='min')
    woe=list(d4['woe'].values)
    print(d4)
    print('-'*30)
    cut=[]
    #float('inf') 为正无穷,而不是直接写inf
    cut.append(float('-inf'))
    for i in range(1,n+1):
        qua=X.quantile(i/(n+1))
        cut.append(round(qua,4))
    cut.append(float('inf'))
    return d4,iv,woe,cut
#cut是对X取他的四分位,因为Y只有0  1  也不能取四分位。n=3因为最后有n-1,所以实际上是分成了四个桶,woe是四个值。goodattribute是好的属性的意思
dfx1,ivx1,woex1,cutx1=mono_bin(train['SeriousDlqin2yrs'],train['RevolvingUtilizationOfUnsecuredLines'],n=10)
dfx2, ivx2,woex2,cutx2=mono_bin(train['SeriousDlqin2yrs'], train['age'], n=10)
dfx4, ivx4,woex4,cutx4 =mono_bin(train['SeriousDlqin2yrs'],train['DebtRatio'], n=20)
dfx5, ivx5,woex5,cutx5=mono_bin(train['SeriousDlqin2yrs'], train['MonthlyIncome'], n=10)
123456789101112131415161718192021222324252627282930313233343536373839
123456789101112131415161718192021222324252627282930313233343536373839

部分输出结果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-thOXDDP8-1637058396058)(https://www.pianshen.com/images/580/a80bd407b399425c712c93de9910401c.png)]

  • 针对不能最优分箱的变量,分箱如下:
def self_bin(Y,X,cat):
    good=Y.sum()
    bad=Y.count()-good
    d1=pd.DataFrame({'X':X,'Y':Y,'Bucket':pd.cut(X,cat)})
    d2=d1.groupby(['Bucket'])
    d3=pd.DataFrame(d2['X'].min(),columns=['min'])
    d3['min']=d2['X'].min()
    d3['max']=d2['X'].max()
    d3['sum']=d2['Y'].sum()
    d3['total']=d2['Y'].count()
    d3['rate']=d2['Y'].mean()
    d3['goodattribute']=d3['sum']/good
    d3['badattribute']=(d3['total']-d3['sum'])/bad
    d3['woe']=np.log(d3['goodattribute']/d3['badattribute'])
    iv=((d3['goodattribute']-d3['badattribute'])*d3['woe']).sum()
    d4=d3.sort_index(by='min')
    print(d4)
    print('-'*40)
    woe=list(d3['woe'].values)
    return d4,iv,woe

ninf=float('-inf')
pinf=float('inf')
cutx3=[ninf,0,1,3,5,pinf]
cutx6 = [ninf, 1, 2, 3, 5, pinf]
cutx7 = [ninf, 0, 1, 3, 5, pinf]
cutx8 = [ninf, 0,1,2, 3, pinf]
cutx9 = [ninf, 0, 1, 3, pinf]
cutx10 = [ninf, 0, 1, 2, 3, 5, pinf]
    
dfx3,ivx3,woex3=self_bin(train['SeriousDlqin2yrs'],train['NumberOfTime30-59DaysPastDueNotWorse'],cutx3)
dfx6, ivx6 ,woex6= self_bin(train['SeriousDlqin2yrs'], train['NumberOfOpenCreditLinesAndLoans'], cutx6)
dfx7, ivx7,woex7 = self_bin(train['SeriousDlqin2yrs'], train['NumberOfTimes90DaysLate'], cutx7)
dfx8, ivx8,woex8 = self_bin(train['SeriousDlqin2yrs'], train['NumberRealEstateLoansOrLines'], cutx8)
dfx9, ivx9,woex9 = self_bin(train['SeriousDlqin2yrs'], train['NumberOfTime60-89DaysPastDueNotWorse'], cutx9)
dfx10, ivx10,woex10 = self_bin(train['SeriousDlqin2yrs'], train['NumberOfDependents'], cutx10)
123456789101112131415161718192021222324252627282930313233343536
123456789101112131415161718192021222324252627282930313233343536

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3LnR4l4e-1637058396060)(https://www.pianshen.com/images/591/54c7f38ac3f44e02b4cfc48eab2e8e77.png)]

3.2 WOE

如上面两张图中,在分箱之后立即就求了woe,WOE的全称是“Weight of Evidence”,即证据权重。WoE分析, 是对指标分箱、计算各个档位的WoE值并观察WoE值随指标变化的趋势。
WoE的数学定义是:woe=ln(goodattribute/badattribute)。goodattribute计算方式是每个箱子里的好客户数量/数据集里总的好客户数量;badattribute计算方式是每个箱子里的坏客户数量/数据集里总的坏客户数量。
不同的特征,最优分箱后产生不同的箱子个数,每一个区间对应一个woe值。最后得到的woex1是列表中存放着x1特征分箱后所有的woe。

3.3 IV筛选

如上面两张图中,在分箱之后立即就求了该特征的IV(先求了woe,再求了IV),为一个值,其公式为:IV=sum((goodattribute-badattribute)*woe),IV全称Infomation Value,一般用来比较特征的预测能力。IV0.1以上算有预测能力,0.2以上算比较有预测能力了。生成IV图,代码如下:

import matplotlib.pyplot as plt
%matplotlib inline
ivall=pd.Series([ivx1,ivx2,ivx3,ivx4,ivx5,ivx6,ivx7,ivx8,ivx9,ivx10],index=['x1','x2','x3','x4','x5','x6','x7','x8','x9','x10'])

fig=plt.figure()
ax1=fig.add_subplot(111)
ivall.plot(kind='bar',ax=ax1)
plt.show()
12345678
12345678

11
由上图可以看出,DebtRatio、MonthlyIncome、NumberOfOpenCreditLinesAndLoans、NumberRealEstateLoansOrLines和NumberOfDependents变量的IV值明显较低,预测能力差,所以删除。

3.4 变量相关性分析

用经过清洗后的数据看一下变量间的相关性。注意,这里的相关性分析只是初步的检查,进一步检查模型的VI(证据权重)作为变量筛选的依据。 相关性图我们通过Python里面的seaborn包,调用heatmap()绘图函数进行绘制,实现代码如下:

import seaborn as sns
corr=data.corr()
xticks = ['x0','x1','x2','x3','x4','x5','x6','x7','x8','x9','x10']
fig=plt.figure()
fig.set_size_inches(16,6)
ax1=fig.add_subplot(111)
# 默认是0到1的,vmin和vmax可自定义设置
sns.heatmap(corr,vmin=-1, vmax=1 ,cmap='hsv', annot=True, square=True)
ax1.set_xticklabels(xticks,rotation= 0)
plt.show()
12345678910
12345678910

12
由上图可以看出
(1) 各变量之间的相关性是非常小的,不存在多重共线性问题,如果存在多重共线性,即有可能存在两个变量高度相关,需要降维或剔除处理。
(2)可见NumberOfTime30-59DaysPastDueNotWorse,NumberOfTimes90DaysLate和NumberOfTime60-89DaysPastDueNotWorse这三个特征对于我们所要预测的值SeriousDlqin2yrs(因变量)有较强的相关性。

4 模型分析

证据权重(Weight of Evidence,WOE)转换可以将Logistic回归模型转变为标准评分卡格式。在建立模型之前,我们需要将筛选后的变量转换为WoE值,便于信用评分。

4.1 woe转换

我们已经能获取了每个变量的分箱数据和woe数据,只需要根据各变量数据进行替换,实现代码如下:

data = pd.read_csv('data/TrainData.csv')
#value>=cut[0]=负无穷,是肯定的
from pandas import Series
def replace_woe(series,cut,woe):
    list=[]
    i=0
    while i<len(series):
        valuek=series[i]
        j=len(cut)-2
        m=len(cut)-2
        while j>=0:
            if valuek>=cut[j]:
                j=-1
            else:
                j -=1
                m -= 1
        list.append(woe[m])
        i += 1
    return list

#顺序是第一种反着来,
data['RevolvingUtilizationOfUnsecuredLines'] = Series(replace_woe(data['RevolvingUtilizationOfUnsecuredLines'], cutx1, woex1))
data['age'] = Series(replace_woe(data['age'], cutx2, woex2))
data['NumberOfTime30-59DaysPastDueNotWorse'] = Series(replace_woe(data['NumberOfTime30-59DaysPastDueNotWorse'], cutx3, woex3))
data['DebtRatio'] = Series(replace_woe(data['DebtRatio'], cutx4, woex4))
data['MonthlyIncome'] = Series(replace_woe(data['MonthlyIncome'], cutx5, woex5))
data['NumberOfOpenCreditLinesAndLoans'] = Series(replace_woe(data['NumberOfOpenCreditLinesAndLoans'], cutx6, woex6))
data['NumberOfTimes90DaysLate'] = Series(replace_woe(data['NumberOfTimes90DaysLate'], cutx7, woex7))
data['NumberRealEstateLoansOrLines'] = Series(replace_woe(data['NumberRealEstateLoansOrLines'], cutx8, woex8))
data['NumberOfTime60-89DaysPastDueNotWorse'] = Series(replace_woe(data['NumberOfTime60-89DaysPastDueNotWorse'], cutx9, woex9))
data['NumberOfDependents'] = Series(replace_woe(data['NumberOfDependents'], cutx10, woex10))

test= pd.read_csv('data/TestData.csv')
    # 替换成woe
test['RevolvingUtilizationOfUnsecuredLines'] = Series(replace_woe(test['RevolvingUtilizationOfUnsecuredLines'], cutx1, woex1))
test['age'] = Series(replace_woe(test['age'], cutx2, woex2))
test['NumberOfTime30-59DaysPastDueNotWorse'] = Series(replace_woe(test['NumberOfTime30-59DaysPastDueNotWorse'], cutx3, woex3))
test['DebtRatio'] = Series(replace_woe(test['DebtRatio'], cutx4, woex4))
test['MonthlyIncome'] = Series(replace_woe(test['MonthlyIncome'], cutx5, woex5))
test['NumberOfOpenCreditLinesAndLoans'] = Series(replace_woe(test['NumberOfOpenCreditLinesAndLoans'], cutx6, woex6))
test['NumberOfTimes90DaysLate'] = Series(replace_woe(test['NumberOfTimes90DaysLate'], cutx7, woex7))
test['NumberRealEstateLoansOrLines'] = Series(replace_woe(test['NumberRealEstateLoansOrLines'], cutx8, woex8))
test['NumberOfTime60-89DaysPastDueNotWorse'] = Series(replace_woe(test['NumberOfTime60-89DaysPastDueNotWorse'], cutx9, woex9))
test['NumberOfDependents'] = Series(replace_woe(test['NumberOfDependents'], cutx10, woex10))
1234567891011121314151617181920212223242526272829303132333435363738394041424344
1234567891011121314151617181920212223242526272829303132333435363738394041424344

4.2 Logistic 模型建立

import statsmodels.api as sm
Y=data['SeriousDlqin2yrs']
X=data.drop(['SeriousDlqin2yrs','DebtRatio','MonthlyIncome', 'NumberOfOpenCreditLinesAndLoans','NumberRealEstateLoansOrLines','NumberOfDependents'],axis=1)

X1=sm.add_constant(X)
logit=sm.Logit(Y,X1)
result=logit.fit()
print(result.summary())
12345678
12345678

假设显著性水平设定为0.01,由上图可知,逻辑回归各变量都已通过显著性检验,满足要求

4.3 模型验证

要验证模型的预测能力,我门通过ROC曲线和AUC来评估模型的拟合能力。

from sklearn.metrics import roc_curve,auc
import matplotlib
matplotlib.rcParams['font.sans-serif'] = ['FangSong']    # 指定默认字体
matplotlib.rcParams['axes.unicode_minus'] = False
Y_test=test['SeriousDlqin2yrs']
X_test=test.drop(['SeriousDlqin2yrs','DebtRatio','MonthlyIncome', 'NumberOfOpenCreditLinesAndLoans','NumberRealEstateLoansOrLines','NumberOfDependents'],axis=1)

#通过ROC曲线和AUC来评估模型的拟合能力。
X2=sm.add_constant(X_test)
resu=result.predict(X2)
fpr,tpr,threshold=roc_curve(Y_test,resu)
# %f,%d,%s输出    
rocauc=auc(fpr,tpr)
plt.plot(fpr,tpr,'b',label='AUC=%0.2f'% rocauc)
plt.legend(loc='lower right')
plt.plot([0,1],[0,1],'r--')
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.show()
12345678910111213141516171819
12345678910111213141516171819

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-O3EZtfCI-1637058396067)(https://www.pianshen.com/images/674/6d3ab98cfc57d85067cb8cccc7eeb81a.png)]
从上图可知,AUC值为0.85,说明模型的预测能力较好,正确率较高。证明了用当前这五个特征,去构成信用评分卡的一部分分值是有效的,预测能力是较好的。

5 信用评分卡构建

将Logistic模型转换为标准评分卡的形式。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7vA0g6y5-1637058396069)(https://www.pianshen.com/images/312/18da5c262b90627ce78ff2c57e168c00.JPEG)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-e8oBbCMu-1637058396070)(https://www.pianshen.com/images/235/7e442e6d7b8b40c961b3ffccf02a4b1b.JPEG)]

  • 依据以上论文资料得到:
    a=log(p_good/P_bad)
    Score = offset + factor * log(odds)
    在建立标准评分卡之前,我们需要选取几个评分卡参数:基础分值、 PDO(比率翻倍的分值)和好坏比。在建立标准评分卡之前,我们需要选取几个评分卡参数:基础分值、 PDO(比率翻倍的分值)和好坏比。 这里, 我们取600分为基础分值,PDO为20 (每高20分好坏比翻一倍),好坏比取20。
  • 个人总评分= 基础分+ 各部分得分
# 计算分数函数
def get_score(coe,woe,p):
    scores=[]
    for w in woe:
        score=round(coe*w*p,0)
        scores.append(score)
    return scores

# 部分评分x1,x2,x3,x7,x9
# j和m相当于j是移动光标,m是跟着j,确定数的
def compute_score(series,cut,scores):
    i=0
    list=[]
    while i<len(series):
        value=series[i]
        j=len(cut)-2
        m=len(cut)-2
        while j>=0:
            if value>=cut[j]:
                j=-1
            else:
                j=j-1
                m=m-1
        list.append(scores[m])
        i=i+1  
    return list
# list就是再x1里面挑一个值,这个值和series【i】是对应的
#score是等于模型系数*woe(一个woe对应一个score)*p值(比例因子) 

coe=[9.738849,0.638002,0.505995,1.032246,1.790041,1.131956]      # 回归系数
import math
p = 20 / math.log(2)     #p值(比例因子) 
q = 600 - 20 * math.log(20) / math.log(2)    # 
basescore = round(q + p * coe[0], 0)
# 因为第一个是常数项
#构建评分卡时候只需要选出那些,IV值高的特征就行,最后相加得到总分
x1 = get_score(coe[1], woex1, p)
x2 = get_score(coe[2], woex2, p)
x3 = get_score(coe[3], woex3, p)
x7 = get_score(coe[4], woex7, p)
x9 = get_score(coe[5], woex9, p)
# x1的四个值分别对应cut的四个区间.PDO Point Double Odds,    就是好坏比翻一倍, odds就是好坏比
print(x1)
print(x2)
print(x3)
print(x7)
print(x9)
test1=pd.read_csv('data/TestData.csv')
# 先构建好Series再加上也可以
# round可能要用到import math.
# 只需要对test计算分值,因为我们前面构建模型用的是train,计算分值要用test
test1['BaseScore']=Series(np.zeros(len(test1))+basescore)
test1['x1']=Series(compute_score(test1['RevolvingUtilizationOfUnsecuredLines'],cutx1,x1))
test1['x2'] = Series(compute_score(test1['age'], cutx2, x2))
test1['x3'] = Series(compute_score(test1['NumberOfTime30-59DaysPastDueNotWorse'], cutx3, x3))
test1['x7'] = Series(compute_score(test1['NumberOfTimes90DaysLate'], cutx7, x7))
test1['x9'] = Series(compute_score(test1['NumberOfTime60-89DaysPastDueNotWorse'], cutx9, x9))
test1['score']= test1['BaseScore']+test1['x1']+test1['x2']+test1['x3']+test1['x7']+test1['x9']
test1.to_csv('data/scoredata.csv')
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859

[24.0, 22.0, 5.0, -20.0]
[-8.0, -6.0, -4.0, -3.0, -1.0, 3.0, 7.0, 14.0, 16.0]
[16.0, -27.0, -52.0, -70.0, -80.0]
[20.0, -102.0, -142.0, -166.0, -160.0]
[9.0, -60.0, -88.0, -95.0]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Lwvx0efT-1637058396071)(https://www.pianshen.com/images/191/1ceded54157b50c54a455c62e6503e4f.png)]

test1.loc[:,['SeriousDlqin2yrs','BaseScore', 'x1', 'x2', 'x3', 'x7', 'x9', 'score']].head()
1
1

8 总结及展望

本文通过对kaggle上的数据Give Me Some Credit的挖掘分析,结合信用评分卡的建立原理,通过数据预处理、变量选择、建模分析预测等方法,使用了随机森林算法拟合了缺失值,使用pandas包对数据进行了清理,并使用matplotlib、seaborn绘图包将数据可视化,且使用了Logistic回归模型,最后利用模型验证过的部分特征,创建了一个简单的信用评分系统。

9 参考文献

1.(https://zhuanlan.zhihu.com/p/28322270)
2(https://www.jianshu.com/p/f931a4df202c)
3. (https://zhuanlan.zhihu.com/p/42129141)
4.(https://www.cnblogs.com/hhh5460/p/5186226.html)
5.https://blog.csdn.net/xjpcsdn/article/details/82938838

基于Python的信用评分卡建模分析就为大家介绍到这里了,
欢迎各位同学报名<python金融风控评分卡模型和数据分析微专业课>,学习更多相关知识。

  • 10
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
以下是一个简单的 Python 信用评分建模过程的代码示例: ```python import pandas as pd import numpy as np import matplotlib.pyplot as plt import seaborn as sns from sklearn.model_selection import train_test_split from sklearn.linear_model import LogisticRegression from sklearn.metrics import confusion_matrix, classification_report # 读入数据 data = pd.read_csv("credit_data.csv") # 数据清洗 data = data.dropna() # 特征工程 data['age'] = data['age'].apply(lambda x: abs(x)) # 处理异常值 data['income'] = np.log(data['income']) # 对收入进行对数变换 data['payment_delay_monthly'] = data.loc[:, 'pay_jan':'pay_dec'].sum(axis=1) # 计算每月延迟付款总数 data = data.drop(['pay_jan', 'pay_feb', 'pay_mar', 'pay_apr', 'pay_may', 'pay_jun', 'pay_jul', 'pay_aug', 'pay_sep', 'pay_oct', 'pay_nov', 'pay_dec'], axis=1) # 特征选择 X = data.drop(['default'], axis=1) y = data['default'] # 划分训练集和测试集 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=0) # 建立模型 logreg = LogisticRegression() logreg.fit(X_train, y_train) # 预测评估 y_pred = logreg.predict(X_test) print(confusion_matrix(y_test, y_pred)) print(classification_report(y_test, y_pred)) ``` 上述代码,首先读入了一个名为 `credit_data.csv` 的数据集。然后对数据进行了清洗和特征工程处理,包括处理异常值、对收入进行对数变换、计算每月延迟付款总数等。接着进行特征选择,将 `default` 列作为标签,其余列作为特征。然后使用 `train_test_split` 将数据集划分为训练集和测试集。最后使用 `LogisticRegression` 模型进行建模,并对结果进行预测评估
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值