使用R建立银行贷款违约模型

2023-11-12

一、项目背景及目的

 使用R语言对银行的个人贷款是否违约进行预测,帮助业务部门及时发现问题,以避免损失。

二、数据说明

 本项目数据集来自《数据科学实战:Python篇》。数据集包含8个表:账户表accounts、信用卡表card、客户信息表clients、权限分配表disp、人口地区统计表district、贷款表loans、支付订单表order、交易表trans。
  贷款表(Loans)是该项目问题的核心数据表,每个贷款帐户只有一条记录,故将所有维度的信息归结到贷款表(LOANS)上。首先提取的自变量是客户基本信息:性别、年龄等。客户的人口信息保存在客户信息表(ClIENTS)中,但是该表是以客户为主键的,需要和权限分配表(DISP)相连接才可以获得账号级别的信息。然后提取借款人居住地情况,需要连接地区表(district)。第三步提取行为信息:账户平均余额、余额的标准差、变异系数、平均入账和平均支出的比例、贷存比等。

三、数据处理

 贷款(Loans)表中的还款状态(status)变量记录了客户的贷款偿还情况,其中A代表合同终止且正常还款,B代表合同终止但是未还款,C代表合同未结束且正常还款,D代表合同未结束但是已经拖欠贷款了。出现贷款拖欠则用1标识,如果始终没有出现违约,则设置为0。显然,响应变量即还款状态为二分类变量,因此选择分类模型中最常使用的算法逻辑回归模型建模。

#数据导入
loan<-read.csv("/Users/linda/Desktop/predict-loan-defaulters/loans.csv",header = TRUE,stringsAsFactors = F,fileEncoding="GBK")
account<-read.csv("/Users/linda/Desktop/predict-loan-defaulters/accounts.csv",header = TRUE,stringsAsFactors = F,fileEncoding="GBK")
card<-read.csv("/Users/linda/Desktop/predict-loan-defaulters/card.csv",header = TRUE,stringsAsFactors = F,fileEncoding="GBK")
client<-read.csv("/Users/linda/Desktop/predict-loan-defaulters/clients.csv",header = TRUE,stringsAsFactors = F,fileEncoding="GBK")
disp<-read.csv("/Users/linda/Desktop/predict-loan-defaulters/disp.csv",header = TRUE,stringsAsFactors = F,fileEncoding="GBK")
district<-read.csv("/Users/linda/Desktop/predict-loan-defaulters/district.csv",header = TRUE,stringsAsFactors = F,fileEncoding="GBK")
trans<-read.csv("/Users/linda/Desktop/predict-loan-defaulters/trans.csv",header = TRUE,stringsAsFactors = F,fileEncoding="GBK")
order<-read.csv("/Users/linda/Desktop/predict-loan-defaulters/order.csv",header = TRUE,stringsAsFactors = F,fileEncoding="GBK")

##数据转化
account$date<-as.Date(account$date)
card$issued<-as.Date(card$issued)
card$type<-as.factor(card$type)
client$sex<-as.factor(client$sex)
client$birth_date<-as.Date(client$birth_date)
disp$type<-as.factor(disp$type)
loan$date<-as.Date(loan$date)
loan$status<-as.factor(loan$status)
trans$date<-as.Date(trans$date)

#去掉trans表格的千分位和美元符号,然后转化成数值类型
#install.packages('https://cran.rstudio.com/bin/macosx/el-capitan/contrib/3.6/stringr_1.4.0.tgz',repos = NULL)
library(stringr)
class(trans$amount)
class(trans$balance)
str(loan)  
trans$balance<-gsub(",","",trans$balance)
trans$amount<-gsub(",","",trans$amount)
trans$amount<-as.numeric(gsub("\\$","",trans$amount))
trans$balance<-as.numeric(gsub("\\$","",trans$balance))

#有数据框结构可知贷款状态有A、B、C、D共四种,分别数字化赋值
loan$new_status[loan$status=='A']<-'0'
loan$new_status[loan$status=='B']<-'1'
loan$new_status[loan$status=='C']<-'2'
loan$new_status[loan$status=='D']<-'1'
loan$new_status<-as.factor(loan$new_status)

#根据不同表格的字段对应关系进行合并
data=merge(loan,disp,by.x = "account_id",by.y = "account_id",all.x = TRUE)
data=data[data$type=="所有者",]  #只有所有者才有权限进行贷款
data=merge(data,client,by.x = "client_id",by.y = "client_id",all.x = TRUE)
data=merge(data,district,by.x="district_id",by.y = "A1",all.x = TRUE)
data_temp=merge(loan,trans,by.x = "account_id",by.y = "account_id",all=FALSE)
#data_temp的date.x指loan中贷款日期,date.y指trans的交易日期
#取一年的交易数据,评估贷款日期前365天至贷款日期前一天的交易数据
data_temp=data_temp[data_temp$date.x>data_temp$date.y&data_temp$date.x<data_temp$date.y+365,]
#计算每个贷款账户贷款前一年的平均账户余额(财富水平)、余额的标准差(财富稳定程度)和变异系数(财富的相对稳定程度)
mean=aggregate(data_temp[,14],by=list(data_temp[,1]),mean)
sd=aggregate(data_temp[,14],by=list(data_temp[,1]),sd)
names(mean)=c("account_id","mean")
names(sd)=c("account_id","sd")
data_temp1<-merge(mean,sd,by.x = "account_id",by.y = "account_id",all = TRUE)
data_temp1$cv<-data_temp1$sd/data_temp1$mean

#分别计算平均入账和平均支出及支出占收入的比例
amount<-aggregate(data_temp[,13],by=list(data_temp[,1],data_temp[,11]),sum) #根据账户ID和借贷类型分别汇总同一个账户的入账金额和支出金额
names(amount)<-c("account_id","type","amount")
unique(amount$type)
pay<-amount[amount$type=="借",]
income<-amount[amount$type=="贷",]
colnames(pay)<-c("account_id","type","pay")
colnames(income)<-c("account_id","type","income")
data_temp2<-merge(income,pay,by.x = "account_id",by.y = "account_id",all=TRUE)#得到每个账户ID下的还款总金额及借款金额总金额

#判断有无缺失值
unique(is.na(data_temp2$pay))
unique(is.na(data_temp2$income))
data_temp2[is.na(data_temp2$pay)==TRUE,5]=0
#计算支出占收入的比例
data_temp2$ratio<-data_temp2$pay/data_temp2$income


#将平均帐户余额及其标准差和变异系数、平均入账和平均支出的比例与data数据表合并
data1<-merge(data,data_temp1,by.x="account_id",by.y="account_id",all=TRUE)
data1<-merge(data1,data_temp2,by.x="account_id",by.y="account_id",all=TRUE)
#计算贷存比、贷收比
data1$r_lb<-data1$amount/data1$mean
data1$r_lincome<-data1$amount/data1$income
head(data1$r_lb)
head(data1$r_lincome)

#缺失值处理
#判断缺失值个数,这里A12、A15、type.y存在缺失值
> sapply(data1, function(x) sum(is.na(x)))
 account_id district_id   client_id     loan_id        date 
          0           0           0           0           0 
     amount    duration    payments      status  new_status 
          0           0           0           0           0 
    disp_id        type         sex  birth_date         GDP 
          0           0           0           0           0 
         A4         A10         A11         A12         A13 
          0           0           0           8           0 
        A14         A15         a16        mean          sd 
          0           8           0           0           0 
         cv      type.x      income      type.y         pay 
          0           0           0           3           0 
      ratio        r_lb   r_lincome 
          0           0           0 
#缺失值A12、A15用均值替代
data1$A12[is.na(data1$A12)] <- mean(data1$A12,na.rm=T)
data1$A15[is.na(data1$A15)]<-mean(data1$A12,na.rm=T)

四、构建逻辑回归模型

 提取贷款状态为C(new_status为2)的用于预测,其他样本随机抽样,建立训练集和测试集。

data2<-data1[,c(6,7,10,15,16,17,18,19,20,21,22,23,24,25,26,28,30,31,32,33)]
colnames(data2)
data_model<-data2[data2$new_status!=2,]
for_predict<-data2[data2$new_status==2,]
#随机抽取模型数据集中70%的行数据作为训练集建立模型,剩余的数据作为测试数据
n<-nrow(data_model)
rnd<-sample(n,n*.70)
train<-data_model[rnd,]
test<-data_model[-rnd,]

##使用向前逐步回归法进行逻辑回归建模
formula<new_status~GDP+A4+A10+A11+A12+amount+duration+A13+A14+A15+a16+mean+sd+cv+income+pay+r_lb+r_lincome+ratio
model<-glm(formula,data = train,family = binomial(link = logit))
forward_model<-step(model,direction = "forward")
summary(forward_model)

##使用向后逐步回归法进行逻辑回归建模     
backward_model<-step(model,direction="backward")
summary(backward_model)

#逐步回归
both_model<-step(model,direction="both")
summary(both_model)

三种回归模型结果如下:
1.向前回归
在这里插入图片描述
2.向后回归在这里插入图片描述
3.逐步回归
在这里插入图片描述

 从模型结果可知,上述三种方法的模型结果基本保持一致,三种方法预测的自变量A14(贷款者当地1000人中有多少企业家)、duration(贷款期限)、r_lb(申请贷款前一年的贷存比)、mean(平均存款余额)、 sd(存款余额的标准差)、ratio(支出占收入的比重)均是显著的,且回归系数的正负号均符合预期。其中,申请贷款前一年的贷存比、存款余额的标准差、贷款期限与违约正相关。存款余额的均值、贷款者当地1000人中有多少企业家与违约负相关。

五、模型评估

  用测试数据(test)做模型效果评估,以下选用逐步回归模型作为预测模型。通过计算准确率和ROC曲线下面积(AUC)来评估模型效果。

#用测试集做模型评估
pre<-predict(both_model,test,type = "response")
#在预测数据集中,响应变量为1的概率大于0.5则认为违约,记为1,小于0.5为不违约,记为0。
test$pre_new_status<-ifelse(pre>0.5,1,0)
table(test$new_status,test$pre_new_status)

#准确率计算,
#sum_diag表示对角线元素和即test数据集的实际值与预测值相一致的总个数
sum_diag<-sum(diag(table(test$new_status,test$pre_new_status)))
sum<-sum(table(test$new_status,test$pre_new_status))
accuracy<-sum_diag/sum
accuracy  #计算出准确率85%

#ROC曲线评估
#install.packages("/Users/linda/Downloads/sjmisc_2.8.3.tgz",repos = NULL)
library(sjmisc)
#install.packages("/Users/linda/Downloads/pROC_1.16.1.tgz",repos = NULL)
library(pROC)
roc_curve<-roc(test$new_status~pre)
x<-1-roc_curve$specificities
y<-roc_curve$sensitivities
plot(x=x,y=y,xlim=c(0,1),ylim=c(0,1),xlab = '1-specificity',ylab = 'Sensitivity',main='ROC Curve',type='l',lwd=2.5)
abline(a=0,b=1,col='black')
auc<-roc_curve$auc
text(0.5,0.4,paste('AUC:',round(auc,digits = 2)),col='red')

在这里插入图片描述
 可以看到模型的准确率为85%,模型的ROC曲线非常接近左上角,其曲线下面积(AUC)为0.87,这说明模型的分类能力较强。

六、模型预测及应用

 我们可以通过该模型得到每笔贷款的违约预测概率,根据概率可以知道这些贷款客户中哪些人的违约可能性较高,需要业务人员重点关注,提前想出应对措施。

#模型预测及应用
for_predict$predict<-predict(both_model,for_predict,type="response")
View(for_predict)

部分预测结果如图:
在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用R建立银行贷款违约模型 的相关文章

  • 绘制 Cox 回归的 Kaplan-Meier 图

    我使用 R 中的以下代码设置了一个 Cox 比例风险模型来预测死亡率 添加协变量 A B 和 C 只是为了避免混淆 即年龄 性别 种族 但我们真正对预测变量 X 感兴趣 X 是一个连续变量 cox model lt coxph Surv t
  • 如何纠正 data.frame 上的字符编码

    我有一个像这样的数据框 data names lt data frame DATA c 1 5 rownames data names lt c IV xc1N JOS xc9 LUC xcdA RAM xd3N TO xd1O data
  • 为什么 sapply 的缩放速度比样本大小的 for 循环慢?

    假设我想采用向量 X 2 1 N 并将 e 计算为每个元 素的指数 是的 我认识到最好的方法就是通过向量化 exp X 但这样做的目的是将 for 循环与 sapply 进行比较 我通过逐步尝试三种方法 一种使用 for 循环 两种以不同方
  • 如何在 R 中的 for 循环内将值存储在向量中

    我正在开始使用 R 但我对以下问题感到非常沮丧 我试图将 for 循环内完成的某些计算的值存储到我之前定义的向量中 问题是如何进行索引 因为for循环迭代代码的次数取决于用户的输入 所以变量i不一定要从1开始 它可以从80开始 for举个例
  • `dplyr::_join` 函数的命名向量“by”参数[重复]

    这个问题在这里已经有答案了 我正在写一个函数dplyr join两个数据框by不同的列 第一个数据帧的列名称动态指定为函数参数 我相信我需要使用rlang准引用 元编程 但未能找到可行的解决方案 我很感激任何建议 library dplyr
  • `as.matrix` 和 `as.data.frame` S3 方法与 S4 方法

    我注意到定义as matrix or as data frame作为 S4 类的 S3 方法 使例如lm formula objS4 and prcomp object 开箱即用 如果它们被定义为 S4 方法 则这不起作用 为什么将方法定义
  • 行对名称中具有特定模式的列求和

    我有一个像这样的数据表 DT lt ata table data table ref rep 3L 4L nb 12 15 i1 c 3 1e 05 0 044495 0 82244 0 322291 i2 c 0 000183 0 155
  • 闪亮的应用程序包:css 和所有 www/ 目录内容

    我正在尝试将 Shiny 应用程序转换为 R 包 但我在处理有关 www 目录以及 松散 文件的所有问题时遇到了问题 我闪亮的应用程序运行得很好 但是当我尝试 打包它 时 它不起作用 我闪亮的应用程序目录 my shiny app R ut
  • 在 Shiny 中显示反应式 htmlTable 表格

    我正在制作我的第一个 Shiny 应用程序 但找不到任何有关如何显示使用 htmlTable 包创建的表格的示例 我基本上想在按下按钮时创建一个表格并显示它 Shiny 显示 html 代码而不是表格 我不知道用什么替换服务器部分中的 re
  • R,使用具有两种以上可能性的二项式分布

    我知道这可能是基本的 但我似乎有一个心理障碍 假设您想要计算在一个骰子上掷出 4 5 或 6 的概率 在 R 中 这很简单 sum 1 6 1 6 1 6 这给出了 1 2 这是正确答案 然而 我内心深处 可能应该保留的地方 认为我应该能够
  • 如何按定义的顺序将图像合并到一个文件中

    我有大约 100 张图像 png 我不想手动执行此操作 而是希望将它们按照定义的顺序 基于文件名 并排放置在一个 pdf 中 每行 12 个图像 有人有什么建议吗 我按照下面托马斯告诉我的方法尝试了 它把它们贴在旁边有一个黑边 我怎样才能去
  • R Shinydashboard 自定义 CSS 到 valueBox

    我一直在尝试将 valueBox 的颜色更改为自定义颜色 超出 validColors 中可用的颜色 但一直无法这样做 我知道有一种方法可以使用标签来包含自定义 CSS 但是我无法将它们放在正确的位置 ui lt dashboardPage
  • 在 RMarkdown 输出到 PDF 时缩进而不添加项目符号点或编号

    之前有人问过如何在没有项目符号的情况下缩进文本 RMarkdown 中的点 但这是针对 HTML 输出的 在 RMarkdown 中缩进而不添加项目符号点或数字 https stackoverflow com questions 47087
  • 从数据框中绘制多条平滑线

    我对 R 比较陌生 我正在尝试绘制从 csv 文件加载的数据框 数据由 6 列组成 如下所示 xval col1 col2 col3 col4 col5 第一列 xval 由一系列单调递增的正整数 例如 10 40 60 等 组成 其他列
  • R中IF函数的使用

    我正在短跑ifR 中的函数 但收到以下警告消息 In if runif 50 0 1 lt 0 69 the condition has length gt 1 and only the first element will be used
  • 平滑连续 2D 点

    UPDATE 感谢 user20650和 李哲源Zheyuan Li 这是我想出的解决方案 Example data set df 3600 observations points Create a vector of the cumula
  • 如何在 R 中的 dygraph 标题中使用 UTF-8 字符

    使用 Rstudio Windows8 当我使用 dygraph 函数绘制时间序列时 在尝试在主标题中使用 UTF 8 字符时遇到问题 library dygraphs dygraph AirPassengers main T tulo 这
  • R 中的数据框操作 - 将单元格向左移动并删除 NA

    我有一个数据框 其列由随机分布的值和 NA 组成 如下所示 a lt c S E NA S NA b lt c A NA M G K c lt c I NA NA NA L meh lt dataframe a b c 1 2 3 4 5
  • 如何使用plotmath更新ggplot图例标签

    我正在尝试更新ggplot要使用的图例标签plotmath但是 当我这样做时 它将之前组合的图例分成两部分 通过一个例子可能更容易理解 test data and the default plot gives the correct col
  • 斯皮尔曼相关性和联系

    我正在一小组配对排名上计算斯皮尔曼的 rho 斯皮尔曼因处理领带不当而闻名 例如 取2组8个排名 即使两组中有6个是平局 相关性仍然很高 gt cor test c 1 2 3 4 5 6 7 8 c 0 0 0 0 0 0 7 8 met

随机推荐