一 . 项目介绍

1.1 概述

如今在银行、消费金融公司等各种贷款业务机构,普遍使用信用评分,对客户实行打分制,以期对客户有一个优质与否的评判。其实信用评分卡还分A,B,C卡三类:

A卡(Application score card)申请评分卡

B卡(Behavior score card)行为评分卡

C卡(Collection score card)催收评分卡

信用评分是指根据银行客户的各种历史信用资料,利用一定的信用评分模型,得到不同等级的信用分数,根据客户的信用分数,授信者可以通过分析客户按时还款的可能性,据此决定是否给予授信以及授信的额度和利率。

1.2 数据来源

本项目数据来源于kaggle竞赛Give Me Some Credit,有15万条样本数据。

下载地址:

https://www.kaggle.com/c/GiveMeSomeCredit/data

1.3 目标

一般申请信用评分卡的构建

二 . 数据预处理

2.1 数据描述

数据属于个人消费类贷款,只考虑评分卡最终实施时能够使用到的数据应从如下一些方面获取数据:

  • 基本属性:包括了借款人当时的年龄。

  • 偿债能力:包括了借款人的月收入、负债比率。

  • 信用往来:两年内35-59天逾期次数、两年内60-89天逾期次数、两年内90天或高于90天逾期的次数。

  • 财产状况:包括了开放式信贷和贷款数量、不动产贷款或额度数量。

  • 贷款属性:暂无。

  • 其他因素:包括了借款人的家属数量(不包括本人在内)。

2.2 数据处理

首先去掉原数据中的顺序变量,即第一列的id变量。由于要预测的是SeriousDlqin2yrs变量,因此将其设为响应变量y,其他分别设为x1~x10变量。

## 导入数据

rm(list = ls())

setwd('D:\\评分卡模型')

getwd()

a<-read.csv('cs_training.csv',header = T,stringsAsFactors = F)

a

str(a)

## 给列名重命名

colnames(a)

colnames(a)<-c("id","y","x1","x2","x3","x4","x5","x6","x7","x8","x9","x10")

summary(a)

2.3 缺失值分析及处理

在得到数据集后,我们需要观察数据的分布情况,因为很多的模型对缺失值敏感,因此观察是否有缺失值是其中很重要的一个步骤。在正式分析前,我们先通过图形进行对观测字段的缺失情况有一个直观的感受。

# 查看数据集缺失数据

md.pattern(a)

monthlyincome(X5)列共有缺失值29731个,numberofdependents(X10)有3924个。

# 对x5缺失处理

x5<-a$x5

x5_var<-c(

var="x5",

mean=mean(x5,na.rm=TRUE) ,   #na.rm=TRUE去除NA的影响

median=median(x5,na.rm=TRUE) ,

quantile(x5,c(0,0.01,0.1,0.25,0.5,0.75,0.9,0.99,1),na.rm=TRUE),

max=max(x5,na.rm=TRUE),

missing=sum(is.na(x5))

)

View(t(x5_var))

#用mean填补缺失值

a$x5<-ifelse(is.na(a$x5)==T,6670.2,a$x5)

# 对x10缺失处理

x10<-a$x10

x10_var<-c(

var="x10",

mean=mean(x10,na.rm=TRUE) ,   #na.rm=TRUE去除NA的影响

median=median(x10,na.rm=TRUE) ,

quantile(x10,c(0,0.01,0.1,0.25,0.5,0.75,0.9,0.99,1),na.rm=TRUE),

max=max(x10,na.rm=TRUE),

missing=sum(is.na(x10))

)

View(t(x10_var))

#用mean填补缺失值

a$x10<-ifelse(is.na(a$x10)==T,0.75,a$x10)

对于缺失值的处理方法非常多,例如基于聚类的方法,基于回归的方法,基于均值的方法,其中最简单的方法是直接移除,但是在本文中因为缺失值所占比例较高,直接移除会损失大量观测,因此并不是最合适的方法。在这里,我们使用mean方法对缺失值进行填补。

2.4 异常值处理

# 对x1处理

a$x1<-round(a$x1,2)

x1<-a$x1

x1_var<-c(

var="x1",

mean=mean(x1,na.rm=TRUE) ,   #na.rm=TRUE去除NA的影响

median=median(x1,na.rm=TRUE) ,

quantile(x1,c(0,0.01,0.1,0.25,0.5,0.75,0.9,0.91,0.99,1),na.rm=TRUE),

max=max(x1,na.rm=TRUE),

missing=sum(is.na(x1))

)

View(t(x1_var))

sum(a$x1 >1)#3057

boxplot(x1~y,data=a,horizontal=T, frame=F,

col="lightgray",main="Distribution")

#对x1进行盖帽法处理异常值

block<-function(x,lower=T,upper=T){

if(lower){

q1<-quantile(x,0.01)

x[x<=q1]<-q1

}

if(upper){

q90<-quantile(x,0.90)

x[x>q90]<-q90

}

return(x)

}

a$x1<-block(a$x1)

# 对x2处理

unique(a$x2)

sum(a$x2==0)

a<-a[-which(a$x2==0),]#删除年龄为0的异常记录

x2<-a$x2

x2_var<-c(

var="x2",

mean=mean(x2,na.rm=TRUE) ,   #na.rm=TRUE去除NA的影响

median=median(x2,na.rm=TRUE) ,

quantile(x2,c(0,0.01,0.1,0.25,0.5,0.75,0.9,0.99,1),na.rm=TRUE),

max=max(x2,na.rm=TRUE),

missing=sum(is.na(x2))

)

View(t(x2_var))

boxplot(x2~y,data=a,horizontal=T, frame=F,

col="lightgray",main="Distribution")

#对x2进行盖帽法处理异常值

a$x2<-block(a$x2)

# 对x3处理

unique(a$x3)

x3<-a$x3

x3_var<-c(

var="x3",

mean=mean(x3,na.rm=TRUE) ,   #na.rm=TRUE去除NA的影响

median=median(x3,na.rm=TRUE) ,

quantile(x3,c(0,0.01,0.1,0.25,0.5,0.75,0.9,0.99,1),na.rm=TRUE),

max=max(x3,na.rm=TRUE),

missing=sum(is.na(x3))

)

View(t(x3_var))

boxplot(x3~y,data=a,horizontal=T, frame=F,

col="lightgray",main="Distribution")

##盖帽法

block1<-function(x,lower=T,upper=T){

if(lower){

q1<-quantile(x,0.01)

x[x<=q1]<-q1

}

if(upper){

q99<-quantile(x,0.99)

x[x>q99]<-q99

}

return(x)

}

a$x3<-block1(a$x3)

……其他的变量都是用盖帽法处理的异常值,这里就不再一一列出。

把盖帽法的代码在下面列出来:

##异常值处理

#盖帽法

block<-function(x,lower=T,upper=T){

if(lower){

q1<-quantile(x,0.01)

x[x<=q1]<-q1

}

if(upper){

q99<-quantile(x,0.99)

x[x>q99]<-q99

}

return(x)

}

# 对y进行处理

a$y<-as.numeric(!as.logical(a$y))

2.5 变量分箱

证据权重(Weight of Evidence,WOE)转换可以将Logistic回归模型转变为标准评分卡格式。引入WOE转换的目的并不是为了提高模型质量,只是一些变量不应该被纳入模型,这或者是因为它们不能增加模型值,或者是因为与其模型相关系数有关的误差较大,其实建立标准信用评分卡也可以不采用WOE转换。这种情况下,Logistic回归模型需要处理更大数量的自变量。尽管这样会增加建模程序的复杂性,但最终得到的评分卡都是一样的。用WOE(x)替换变量x。WOE()=ln[(违约/总违约)/(正常/总正常)]。

library(smbinning)

library(prettyR)

# 对X1分箱

x1<-smbinning(a,'y','x1')

x1$ivtable

par(mfrow=c(2,2))

smbinning.plot(x1,option = 'WoE',sub = "x1")

smbinning.plot(x1,option="dist",sub="x1")

smbinning.plot(x1,option="goodrate",sub="x1")

smbinning.plot(x1,option="badrate",sub="x1")

x1$iv

R_iv<-c(x1=x1$iv)

# 对X2分箱

x2<-smbinning(a,'y','x2')

x2$ivtable

smbinning.plot(x2,option = 'WoE',sub = "x2")

smbinning.plot(x2,option="dist",sub="x2")

smbinning.plot(x2,option="goodrate",sub="x2")

smbinning.plot(x2,option="badrate",sub="x2")

x2$iv

R_iv<-c(R_iv,x2=x2$iv)

# 对X3分箱

unique(a$x3)

x3<-smbinning(a,'y','x3')

x3$ivtable

par(mfrow=c(2,2))

smbinning.plot(x3,option="dist",sub="x3")

smbinning.plot(x3,option="WoE",sub="x3")

smbinning.plot(x3,option="goodrate",sub="x3")

smbinning.plot(x3,option="badrate",sub="x3")

x3$iv

R_iv<-c(R_iv,x3=x3$iv)

# 对X4分箱

x4<-smbinning(a,'y','x4')

x4$ivtable

par(mfrow=c(2,2))

smbinning.plot(x4,option="dist",sub="x4")

smbinning.plot(x4,option="WoE",sub="x4")

smbinning.plot(x4,option="goodrate",sub="x4")

smbinning.plot(x4,option="badrate",sub="x4")

x4$iv

R_iv<-c(R_iv,x4=x4$iv)

# 对X5分箱

x5<-smbinning(a,'y','x5')

x5$ivtable

smbinning.plot(x5,option = 'WoE',sub = "NumberRealEstateLoansOrLines")

x5$iv

R_iv<-c(R_iv,x5=x5$iv)

# 对X6分箱

x6<-smbinning(a,'y','x6')

x6$ivtable

par(mfrow=c(2,2))

smbinning.plot(x6,option="dist",sub="x6")

smbinning.plot(x6,option="WoE",sub="x6")

smbinning.plot(x6,option="goodrate",sub="x6")

smbinning.plot(x6,option="badrate",sub="x6")

x6$iv

R_iv<-c(R_iv,x6=x6$iv)

# 对X7分箱

x7<-smbinning(a,'y','x7')

x7$ivtable

par(mfrow=c(1,1))

smbinning.plot(x7,option="dist",sub="x7")

smbinning.plot(x7,option="WoE",sub="x7")

smbinning.plot(x7,option="goodrate",sub="x7")

smbinning.plot(x7,option="badrate",sub="x7")

x7$iv

R_iv<-c(R_iv,x7=x7$iv)

# 对X8分箱

x8<-smbinning(a,'y','x8')

x8$ivtable

par(mfrow=c(2,2))

smbinning.plot(x8,option="dist",sub="x8")

smbinning.plot(x8,option="WoE",sub="x8")

smbinning.plot(x8,option="goodrate",sub="x8")

smbinning.plot(x8,option="badrate",sub="x8")

par(mfrow=c(1,1))

x8$iv

R_iv<-c(R_iv,x8=x8$iv)

# 对X9分箱

x9<-smbinning(a,'y','x9')

x9$ivtable

par(mfrow=c(2,2))

smbinning.plot(x9,option="dist",sub="x9")

smbinning.plot(x9,option="WoE",sub="x9")

smbinning.plot(x9,option="goodrate",sub="x9")

smbinning.plot(x9,option="badrate",sub="x9")

par(mfrow=c(1,1))

x9$iv

R_iv<-c(R_iv,x9=x9$iv)

# 对X10分箱

x10<-smbinning(a,'y','x10')

x10$ivtable

par(mfrow=c(2,2))

smbinning.plot(x10,option="dist",sub="x10")

smbinning.plot(x10,option="WoE",sub="x10")

smbinning.plot(x10,option="goodrate",sub="x10")

smbinning.plot(x10,option="badrate",sub="x10")

par(mfrow=c(1,1))

x10$iv

R_iv<-c(R_iv,x10=x10$iv)

生成分箱后的新列

a2<-a

a2<-smbinning.gen(a2,x1,'R_x1')

a2<-smbinning.gen(a2,x2,'R_x2')

a2<-smbinning.gen(a2,x3,'R_X3')

a2<-smbinning.gen(a2,x4,'R_x4')

a2<-smbinning.gen(a2,x5,'R_x5')

a2<-smbinning.gen(a2,x6,'R_x6')

a2<-smbinning.gen(a2,x7,'R_x7')

a2<-smbinning.gen(a2,x8,'R_X8')

a2<-smbinning.gen(a2,x9,'R_X9')

a2<-smbinning.gen(a2,x10,'R_x10')

a3<-a2[,c(2,13:22)]

三. 构建建模

# 构建逻辑回归模型

cred_mod<-glm(y~.,data = a3,family = binomial())

summary(cred_mod)

四. 构建评分卡


4.1 对变量进行打分

# 对模型的变量进行打分

# score=A-B*log(odds)

cre_scal<-smbinning.scaling(cred_mod,pdo=45,score=800,odds=50)

cre_scal$minmaxscore

cre_scal$logitscaled

4.2 生成每行对应的分数

#生成每行对应的分数

a4<-smbinning.scoring.gen(smbscaled=cre_scal, dataset=a3)

boxplot(Score~y,data=a4,horizontal=T, frame=F, col="lightgray",main="Distribution")

4.3 画ROC曲线

## 画ROC曲线

smbinning.metrics(a4,"Score","y",plot="auc")

模型评估

通常一个二值分类器可以通过ROC(Receiver Operating Characteristic)曲线和AUC值来评价优劣。

很多二元分类器会产生一个概率预测值,而非仅仅是0-1预测值。我们可以使用某个临界点(例如0.5),以划分哪些预测为1,哪些预测为0。得到二元预测值后,可以构建一个混淆矩阵来评价二元分类器的预测效果。所有的训练数据都会落入这个矩阵中,而对角线上的数字代表了预测正确的数目,即true positive + true nagetive。同时可以相应算出TPR(真正率或称为灵敏度)和TNR(真负率或称为特异度)。我们主观上希望这两个指标越大越好,但可惜二者是一个此消彼涨的关系。除了分类器的训练参数,临界点的选择,也会大大的影响TPR和TNR。有时可以根据具体问题和需要,来选择具体的临界点。

如果我们选择一系列的临界点,就会得到一系列的TPR和TNR,将这些值对应的点连接起来,就构成了ROC曲线。ROC曲线可以帮助我们清楚的了解到这个分类器的性能表现,还能方便比较不同分类器的性能。在绘制ROC曲线的时候,习惯上是使用1-TNR作为横坐标即FPR(false positive rate),TPR作为纵坐标。这是就形成了ROC曲线。

而AUC(Area Under Curve)被定义为ROC曲线下的面积,显然这个面积的数值不会大于1。又由于ROC曲线一般都处于y=x这条直线的上方,所以AUC的取值范围在0.5和1之间。使用AUC值作为评价标准是因为很多时候ROC曲线并不能清晰的说明哪个分类器的效果更好,而作为一个数值,对应AUC更大的分类器效果更好。

4.4 生成评分卡并导出

##生成评分卡并导出

scaledcard<-cre_scal$logitscaled[[1]][-1,c(1,2,6)]

scaledcard

scaledcard[,1]<-c(rep("x1",8),rep("x2",9),

rep("x3",3),rep("x4",5),rep("x5",5),

rep("x6",5),rep('x7',2),rep('x8',4),rep('x9',2),rep('x10',4))

write.csv(scaledcard,"card.csv",row.names = F)


4.5 个人评分计算案例


公众号后台回复关键字即可学习

回复 爬虫            爬虫三大案例实战  
回复 Python       1小时破冰入门

回复 数据挖掘     R语言入门及数据挖掘
回复 人工智能     三个月入门人工智能
回复 数据分析师  数据分析师成长之路 
回复 机器学习      机器学习的商业应用
回复 数据科学      数据科学实战
回复 常用算法      常用数据挖掘算法

R语言 | 构建信用评分卡模型相关推荐

  1. R 语言快速构建信用评分卡模型---scorecard包

    前言 R 语言快速构建机器学习,基于某大佬的scorecard包. # github主页 - R版: http://github.com/shichenxie/scorecard # 加载[data. ...

  2. 【风控模型】融合模型Boosting构建信用评分卡模型

    [博客地址]:https://blog.csdn.net/sunyaowu315 [博客大纲地址]:https://blog.csdn.net/sunyaowu315/article/details/ ...

  3. 【风控模型】融合模型Bagging构建信用评分卡模型

    [博客地址]:https://blog.csdn.net/sunyaowu315 [博客大纲地址]:https://blog.csdn.net/sunyaowu315/article/details/ ...

  4. 【风控模型】神经网络DNN算法构建信用评分卡模型

    [博客地址]:https://blog.csdn.net/sunyaowu315 [博客大纲地址]:https://blog.csdn.net/sunyaowu315/article/details/ ...

  5. 信用评分卡模型(R语言)

    贷款风险预测-信用评分卡模型(R语言) 时间:2018年10月9日 本次的分析数据来自Kaggle数据竞赛平台的"give me some credit"竞赛项目.下载地址为:ht ...

  6. 互联网金融信用评分卡模型构建

    互联网金融信用评分卡模型构建 背景介绍 信用风险计量体系包括主体评级模型和债项评级两部分. 主体评级和债项评级均有一系列评级模型组成,其中主体评级模型可用"四张卡"来表示,分别是A ...

  7. 基于Python的信用评分卡模型-give me some credit数据集,AUC 0.93 KS 0.71

    信用风险计量模型可以包括跟个人信用评级,企业信用评级和国家信用评级.人信用评级有一系列评级模型组成,常见是A卡(申请评分卡).B卡(行为模型).C卡(催收模型)和F卡(反欺诈模型). 今天我们展示的是 ...

  8. 3分钟搞明白信用评分卡模型模型验证

    2019独角兽企业重金招聘Python工程师标准>>> 信用评分卡模型在国外是一种成熟的预测方法,尤其在信用风险评估以及金融风险控制领域更是得到了比较广泛的使用,其原理是将模型变量W ...

  9. R语言构建xgboost文本分类模型(bag of words):xgb.cv函数交叉验证确定xgboost模型的最优子树个数、交叉验证获取最优子树之后构建最优xgboost模型并评估模型文本分类效能

    R语言构建xgboost文本分类模型(bag of words):xgb.cv函数交叉验证确定xgboost模型的最优子树个数.交叉验证获取最优子树之后构建最优xgboost模型并评估模型文本分类效能 ...

  10. 分类任务如何用逻辑回归实现_如何用逻辑回归构建金融评分卡模型?(上)

    虽然现在出现了很多性能优秀的分类算法,包括svm,RF,GBDT,DNN等,作为最简单的分类算法,lr依然是工业界主流的分类算法之一.那么lr到底有什么魔力,即使面对如此众多的 "高手&qu ...

最新文章

  1. 微软开源的自动机器学习工具上新了:NNI概览及新功能详解
  2. php exec和query,关于Go SQL中的Query、Exec和Prepare使用对比(附网络抓包)
  3. python 旋转列表
  4. python安装步骤电脑版-超详细的小白python3.X安装教程|Python安装
  5. FreeBSD配置防火墙开启SSH服务
  6. vue 计算属性和data_Vue计算属性原理和使用场景
  7. 【机器学习】从电影数据集到推荐系统
  8. html5 json转字符串,web前端-js小记(5)-字符串及json
  9. 生成clr库_如何使用CLR存储过程发送数据库邮件
  10. bzoj 1625: [Usaco2007 Dec]宝石手镯(01背包)
  11. 详细了解 clientWidth、clientHeight、clientLeft、clientTop 以及几个常用的场景
  12. Java基础-语言简介
  13. 基金使用计划 数学建模 matlab,基金使用计划模型
  14. C语言单元测试之安装gtest教程及一个简单样例
  15. hdu6441 Find Integer
  16. 【天光学术】公共管理研究生应该怎样写好学位论文?
  17. 学计算机每天应该吃什么,上班族长时间看电脑,哪些食物对眼睛好?
  18. svn分支开发与主干合并(branch merge)
  19. 当日、昨日、当周、本周、当月、上个月获取方法
  20. JAVA学习Day3

热门文章

  1. alien rpm deb,ubuntu下安装jdk过程及遇到的问题
  2. Mac cmake命令不可用-bash: cmake: command not found
  3. 从底层分析python中深拷贝和浅拷贝区别
  4. 字节工程师薪资排世界第五,中位数 43 万美元,2021 全球程序员收入报告出炉!...
  5. 因Redis分布式锁造成的P0级重大事故,整个项目组被扣了绩效......,请慎用
  6. 最新Fastjson再爆安全黑洞!可获取服务器权限,快升级!(扩散!!!)
  7. Android技术总监应该干的哪些事
  8. Java系统架构的演化之路
  9. 深圳的小伙伴有福利了!
  10. special word count