评分卡建模学习

评分卡模型 Credit card

1. 模型理论知识

金融行业常用的评分卡模型流程图:
在这里插入图片描述

1.1 数据准备

数据源主要包含行内行外两部分:行内的有客户的基础人口统计特征数据、交易历史数据、信用历史数据等;外部数据有人行征信数据、第三方征信机构数据及社交行为数据等。
人行征信在中小型企业中的征信检测效果比较好

1.2 数据探索

对获得的原始数据进行进一步的探索

  1. 观察样本的总体分布情况,正负样本是否均衡?
    –不均衡样本的处理方法:从数据角度、从算法角度、代价敏感学习
  2. 单变量分布是否满足正态分布?
  3. 变量的缺失情况?
    –缺失值处理方法:整列删除、众数填充
  4. 是否有异常值?
    –箱线图观察、woe变换可以消除异常值影响
  5. 变量间的共线性情况如何,评分卡模型主要是使用逻辑回归算法进行建模,要求变量间共线性尽可能低。
    –热力图观察变量间共线性
  6. 变量规模
    一切就绪后,确定模型的观察期和表现期,确定数据集分割方法,划分训练集和测试集。
  7. 确定坏用户的标准?–逾期多久算违约

1.3 数据预处理

主要工作包括数据清洗、缺失值处理、异常值处理、数据标准化等,主要目的是将获取的原始数据转变成可用于建模的结构化数据。
1. 离散型变量处理方式:无序类别变量、有序类别变量
2. 连续型变量处理方式:分箱

1.4 模型建立

在信用评分卡中一般使用逻辑回归作为主要的模型。
过程主要包括变量分箱、变量的WOE(证据权重)变换和变量选择(IV值)、逻辑回归估算。

(1)类别变量根据类别直接进行WOE变换,连续变量要先进行变量分箱再进行WOE变换。
(2)特征处理阶段主要有两个概念:WOE和IV。
1.分箱——将连续变量离散化,或者将具有很多状态的离散变量合并成少状态
2.分箱的优势:
-对异常值不敏感,如年龄300岁;
-降低模型过拟合风险;
-可以学习到样本的非线性信息?
3.分箱方法:
无监督:等宽、等频、聚类(k-means)
有监督:卡方分箱法、单变量决策树算法(ID3、C4.5、CART)、IV最大化分箱法、best-ks分箱法
creportgen.utils.discretization
4.卡方分箱算法:
卡方分箱是自底向上的(即基于合并的)数据离散化方法。具有最小卡方值的相邻区间合并在一起,直到满足确定的停止准则。

4.1基本思想:对于精确的离散化,相对类频率在一个区间内应当完全一致。因此,如果两个相邻的区间具有非常类似的类分布,则这两个区间可以合并;否则,它们应当保持分开。而低卡方值表明它们具有相似的类分布。

4.2分箱步骤:
1)设定卡方阈值
2)根据要离散的属性值对实例进行排序
3)计算每一对相邻区间的卡方值
4)将卡方值最小的一对区间进行合并
5)重复3)4)两步直至满足停止条件
在这里插入图片描述
停止条件有如下两种选择:
(1)分箱个数:限制最终的分箱个数结果,每次将样本中具有最小卡方值的 区间与相邻的最小卡方区间进行合并,直到分箱个数达到限制条件为止。
(2)卡方阈值:根据自由度和显著性水平得到对应的卡方阈值,如果分箱的各区间最小卡方值小于卡方阈值,则继续合并,直到最小卡方值超过设定阈值为止。

4.3卡方阈值的确定: 根据显著性水平和自由度得到卡方值 ,卡方阈值的自由度为 分箱数-1,显著性水平可以取10%,5%或1%。
例如:有3类,自由度为2,则90%置信度(10%显著性水平)下,卡方的值为4.6。

4.4阈值的意义
类别和属性独立时,有90%的可能性,计算得到的卡方值会小于4.6。 大于阈值4.6的卡方值就说明属性和类不是相互独立的,不能合并。如果阈值选的大,区间合并就会进行很多次,离散后的区间数量少、区间大。
5.分箱后检验Bad Rate单调性
Bad Rate:坏样本率,指的是将特征进行分箱之后,每个bin下的样本所统计得到的坏样本率
bad rate 单调性与不同的特征场景:
在评分卡模型中,对于比较严格的评分模型,会要求连续性变量和有序性的变量在经过分箱后需要保证bad rate的单调性。

  1. 连续性变量:
    在严格的评分卡模型中,对于连续型变量就需要满足分箱后 所有的bin的 bad rate 要满足单调性,只有满足单调新的情况下,才能进行后续的WOE编码
  2. 离散型变量:
    离散化程度高,且无序的变量:
    比如省份,职业等,我们会根据每个省份信息统计得到bad rate 数值对原始省份信息进行编码,这样就转化为了连续性变 量,进行后续的分箱操作,对于经过bad rate编码后的特征数据,天然单调。
    只有当分箱后的所有的bin的bad rate 呈现单调性,才可以进行下一步的WOE编码。
    离散化程度低,且无序的变量:
    比如婚姻状况,只有四五个状态值,因此就不需要专门进行bad rate数值编码,只要求出每个离散值对应的bin的bad rate比例是否出现0或者1的情况,若出现说明正负样本的分布存在极端情况,需要对该bin与其他bin进行合并, 合并过程完了之后 就可以直接进行后续的WOE编码
    有序的离散变量:
    对于学历这种情况,存在着小学,初中,高中,本科,硕士,博士等几种情况,而且从业务角度来说 这些离散值是有序的, 因此我们在分箱的时候,必须保证bin之间的有序性,再根据bad rate 是否为0 或者1的情况 决定是否进行合并,最终将合并的结果进行WOE编码

因此bad rate单调性只在连续性数值变量和有序性离散变量分箱的过程中会考虑。

bad rate要求单调性的原因分析:

  1. 逻辑回归模型本身不要求特征对目标变量的单调性。之所以要求分箱后单调,主要是从业务角度考虑,解释、使用起来方便一点。如果有某个(分箱后的)特征对目标变量不单调,会加剧模型解释型的复杂化
  2. 对于像年龄这种特征,其对目标变量往往是一个U型或倒U型的分布,有些公司/部门/团队是允许变量的bad rate呈(倒)U型的。

5.WOE变换

在这里插入图片描述
其中,pyi是这个组中坏客户(此处风险模型中判别的是好坏客户)占所有样本中所有坏客户的比例,pni是这个组中好客户占样本中所有好客户的比例,#yi是这个组中坏客户的数量,#ni是这个组中好客户的数量,#yT是样本中所有坏客户的数量,#nT是样本中所有好客户的数量。

  WOE表示的实际上是“当前分组中坏客户占所有坏客户的比例”和“当前分组中好客户占所有好客户的比例”的差异。WOE也可以这么理解,他表示的是当前这个组中坏客户和好客户的比值,和所有样本中这个比值的差异。这个差异是用这两个比值的比值,再取对数来表示的。WOE越大,这种差异越大,这个分组里的样本是坏客户的可能性就越大,WOE越小,差异越小,这个分组里的样本是坏客户的可能性就越小。
  sklearn.reportgen.utils.weightOfEvidence

6.IV值计算
计算公式如下:
在这里插入图片描述
有了一个变量各分组的IV值,我们就可以计算整个变量的IV值,方法很简单,就是把各分组的IV相加:
在这里插入图片描述
其中,n为变量分组个数。
IV的特点:
a、对于变量的一个分组,这个分组的好用户和坏用户的比例与样本整体响应和未响应的比例相差越大,IV值越大,否则,IV值越小;
b、极端情况下,当前分组的好用户和坏用户的比例和样本整体的好用户和坏用户的比例相等时,IV值为0;
c、IV值的取值范围是[0,+∞),且,当当前分组中只包含好用户或者坏用户时,IV = +∞。
使用IV其实有一个缺点,就是不能自动处理变量的分组中出现响应比例为0或100%的情况。那么,遇到响应比例为0或者100%的情况,我们应该怎么做呢?建议如下:

(1)如果可能,直接把这个分组做成一个规则,作为模型的前置条件或补充条件;
(2)重新对变量进行离散化或分组,使每个分组的响应比例都不为0且不为100%,尤其是当一个分组个体数很小时(比如小于100个),强烈建议这样做,因为本身把一个分组个体数弄得很小就不是太合理。
(3)如果上面两种方法都无法使用,建议人工把该分组的响应数和非响应的数量进行一定的调整。如果响应数原本为0,可以人工调整响应数为1,如果非响应数原本为0,可以人工调整非响应数为1.
IV值判断变量预测能力的标准
< 0.02: unpredictive,0.02 to 0.1: weak,0.1 to 0.3: medium,0.3 to 0.5: strong,>0.5: suspicious,一般选取大于0.02的

2.R语言实现

信用评分是指根据客户的信用历史资料,利用一定的信用评分模型,得到不同等级的信用分数。
根据客户的信用分数,授信者可以分享客户按时还款的可能性。据此,授信者可以决定是否准予
授信以及授信的额度和利润。
首先,使用logistic和NaiveBayes建模 本文中建模所用到的数据是关于德国公民的信用相关数据,接下来我们针对这个数据集进行模型。

library(ggplot2)
library(klaR)
library(sqldf)
german_credit = read.csv('/Users/Desktop/german_credit.csv',stringsAsFactors = TRUE)
str(german_credit)

数据中的字段主要包含信用(模型中的因变量1为好客户,0为坏客户),账户余额,信用月数,贷款目的等。由于上面的数据大都都是数值型的,故需要根据实际情况将数值变量转换成因子型变量。

for (i in 1:21) german_credit[,i]=as.factor(german_credit[,i])
#个别数据回到数值型
german_credit$Duration <- as.numeric(german_credit$Duration) 
german_credit$CreditAmount <- as.numeric(german_credit$CreditAmount)
german_credit$Age <- as.numeric(german_credit$Age)

根据好客户,坏客户划分数据集

good=german_credit[german_credit$Creditability==1,]
bad=german_credit[german_credit$Creditability==0,]
a=colnames(german_credit)

为了了解数据,我们对数据集中的各变量绘制条形图,这里仅以客户的存款余额为例,如果想了解更多其他变量的分布信息,可以稍作修改下方的代码。

#整体用户的存款余额条形图 AccountBalance在第二列
ggplot(german_credit,aes(german_credit[,2])) +   geom_bar(aes(fill = as.factor(german_credit[,2]))) +    scale_fill_discrete(name=a[2]) +    theme(axis.text.x=element_blank(),axis.ticks.x=element_blank()) +  
      labs(x= a[2],y= "Frequency" , title = "german_credit")
#好客户的条形图
ggplot(good,aes(good[,2])) +   geom_bar(aes(fill = as.factor(good[,2]))) +    scale_fill_discrete(name=a[2]) +    theme(axis.text.x=element_blank(),axis.ticks.x=element_blank()) +  
      labs(x= a[2],y= "Frequency" , title = "german_credit for good")
#坏客户的条形图
ggplot(bad,aes(bad[,2])) +   geom_bar(aes(fill = as.factor(bad[,2]))) +    scale_fill_discrete(name=a[2]) +    theme(axis.text.x=element_blank(),axis.ticks.x=element_blank()) +  
      labs(x= a[2],y= "Frequency" , title = "german_credit for bad")

数据集的划分

set.seed(1)
index = sample(1:2,size=nrow(german_credit),replace = T,prob=c(0.7,0.3))
train_data=german_credit[index==1,]
test_data=german_credit[index==2,]
model1=glm(formula=train_data$Creditability~.,data=train_data,family='binomial',
           control = list(maxit = 100))
summary(model1)
#一开始不放maxit=100的时候说算法不收敛,不聚合,当数据不太好时,经过25次
#迭代可能还不收敛,所以要增大迭代次数。
#从模型结果来看,很多自变量都没有通过显著性检验,接下来利用逐步回归进行改进。
model2=step(object=model1,trace=0)
summary(model2)

经过逐步回归以后,模型的效果得到了一定的提升,留下了很多显著的自变量,同时AIC信息也下降了很多。我们知道,通过logistic模型可以得到每个样本的概率值prob,该概率值是可以根据实际的业务进行调整的,如果风控要求的比较严格,那么就需要把prob的值调的更大。
下面对模型的效果做一个评估,使用混淆矩阵。

# 返回模型在测试集上的概率值
prob <- predict(object = model2, newdata= test_data, type = 'response')
# 根据阈值,将概率值分为两类
pred <- ifelse(prob >= 0.8, 'yes','no')
# 将pred变量设置为因子
pred <- factor(pred, levels =c('no','yes'), order = TRUE)
#混淆矩阵
f <- table(test_data$Creditability, pred) 
f
(89+126)/(89+126+11+78)
pred2 <- ifelse(prob >= 0.5, 'yes','no')
pred2 <- factor(pred2, levels =c('no','yes'), order = TRUE)
#混淆矩阵
f2 <- table(test_data$Creditability, pred) 
f2
(40+186)/(40+186+78)

通过改变模型的阈值,模型的准确性有所提升。当然,我们还可以更换模型,根据实际的业务进行变量的筛选,这个过程会比较繁琐。下面使用贝叶斯方法进行模型预测。

#贝叶斯模型
library(klaR)
model3=NaiveBayes(formula=Creditability~.,data=train_data)
#预测
pre=predict(model3,newdata=test_data)
#posterior存储每个样本为坏客户和好客户的概率值
str(pre$posterior)
#将好客户的概率阈值设为0.8
pred <- ifelse(pre$posterior[,2] >= 0.8, 'yes','no') 
f <- table(test_data$Creditability, pred) 
f

同样0.8的阈值,相比于logistic模型,贝叶斯效果更佳。
Score Card原理

  评分卡模型在国外是一种成熟的预测方法,尤其在信用风险评估以及金融风险控制领域更是得到了比较广泛的使用,其原理是将模型变量离散化之后用WOE编码,在建立模型。ScoreCard用IV值来筛选变量,而且ScoreCard输出为分值。

对IV的直观理解

  IV的全称是Information Value,中文意思是信息价值,或者信息量。从直观逻辑上大体可以这样理解“用IV去衡量变量预测能力”这件事情:我们假设在一个分类问题中,目标变量的类别有两类:Y1,Y2。对于一个待预测的个体A,要判断A属于Y1还是Y2,我们是需要一定的信息的,假设这个信息总量是I,而这些所需要的信息,就蕴含在所有的自变量C1,C2,C3,……,Cn中,那么,对于其中的一个变量Ci来说,其蕴含的信息越多,那么它对于判断A属于Y1还是Y2的贡献就越大,Ci的信息价值就越大,Ci的IV就越大,它就越应该进入到入模变量列表中。

参考链接https://blog.csdn.net/kMD8d5R/article/details/79005347

Naive Bayes 评分卡
首先需要对部分变量作重编码的操作,这个操作在实际工作中需要不断的调试才能得到比较理想的效果。


# 分箱
german_credit$Duration[german_credit$Duration > 40] <- '1'
german_credit$Duration[german_credit$Duration <= 40 & german_credit$Duration > 30] <- '2'
german_credit$Duration[german_credit$Duration<=30 & german_credit$Duration >20] <- '3'
german_credit$Duration[german_credit$Duration<=20] <- '4'
german_credit$Purpose[german_credit$Purpose==8] <- 1
german_credit$Purpose[german_credit$Purpose==10] <- 0
german_credit$Purpose[german_credit$Purpose==4] <- 3
german_credit$Purpose[german_credit$Purpose==9] <- 5


library(sqldf)
#对month变量进行分组统计
a1=sqldf("select `Duration`,count(1) from train_data where `Creditability`=1         group by `Duration` ") 
a2=sqldf("select `Duration`,count(1) from train_data where `Creditability`=0         group by `Duration` ")

#或者用tidyverse得到相似效果
library(tidyverse)
attach(train_data)
train_data%>%group_by(Duration)%>%count()
a1=a1[1:21,]
# 合并数据集
b1=cbind(a1,a2)
head(b1)
# 添加一列变量名称
b1[,5]=colnames(b1)[1]
# 类型转换
b1=as.matrix(b1)

# 对Balance变量进行分组统计
a1=sqldf("select `AccountBalance`,count(1) from train_data where `Creditability`=1         group by `AccountBalance` ") 
a2=sqldf("select `AccountBalance`,count(1) from train_data where `Creditability`=0         group by `AccountBalance` ") 
b2=cbind(a1,a2) 
b2[,5]=colnames(b2)[1] 
b2=as.matrix(b2)
c=rbind(b1,b2)
colnames(c)=c('Bin','Good','Bin','Bad','Variable')
head(c)

接下来还需要把数据框中c中的Good变量

c=as.data.frame(c)
c$Good=as.numeric(c$Good)
c$Bad=as.numeric(c$Bad)
#各组好坏客户之和
c$Total_Number_of_Loans=c$Good+c$Bad
#各组坏客户的比例
c$BadLoans=c$Bad/c$Total_Number_of_Loans

# train_data数据集中好客户和坏客户的数量分别是700和300
# 计算每组好客户占总的好客户的比例
c$Distibution_Good_PG <- c$Good/700
# 计算每组坏客户占总的好客户的比例
c$Distibution_Bad_PB <- c$Bad/300
# 好坏客户比例差异
c$P(GB) <- c$Distibution_Good_PG-c$Distibution_Bad_PB
#计算WOE
c$WOE=log(c$Distibution_Good_PG/c$Distibution_Bad_PB)
#计算IV
c$IV <- c$WOE*c$P(GB)
# 查看统计的c数据集
c
# 汇总计算
aggregate(x=c[,c("IV")],by=list(c$Variable),FUN=sum)
#取出IV值比较大的变量
index5 <- which(c$Variable %in% c('AccountBalance','Duration','PaymentStatusofPreviousCredit','Purpose','Mostvaluableavailableasset','ValueSavings')) 
d <- c[index5,]
str(german_credit)

#算每个变量的最大,与最小WOE与其差值
f1 <- aggregate(x=d[,c("WOE")],by=list(d$Variable),FUN=max) 
f2 <- aggregate(x=d[,c("WOE")],by=list(d$Variable),FUN=min) 
f3 <- cbind(f1,f2) 
colnames(f3) <- c(1,'max',1,'min') 
f3

接下来我们再计算贝叶斯模型的评分:

f3$deff = f3$max-f3$min
#将分数1设置为最大与最小差800分,分数1是用一个常量乘以WOE
ad = 800/sum(f3$deff) 
d$Score1 = d$WOE*ad 
d
  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值