R语言手动绘制随机森林决策曲线

DCA(Decision Curve Analysis)临床决策曲线是一种用于评价诊断模型诊断准确性的方法,在2006年由AndrewVickers博士创建,我们通常判断一个疾病喜欢使用ROC曲线的AUC值来判定模型的准确性,但ROC曲线通常是通过特异度和敏感度来评价,实际临床中我们还应该考虑,假阳性和假阴性对病人带来的影响,因此在DCA曲线中引入了阈概率和净获益的概念。
我们在既往文章中已经介绍了如何通过R语言绘制逻辑回归、cox回归及竞争回归模型的决策曲线。不少粉丝私信问如何绘制随机森林的决策曲线,今天我们来演示一下如何手动绘制随机森林决策曲线,对于其他模型的决策曲线绘制方法,也是通用的。
决策曲线是什么?
在这里插入图片描述
其实决策曲线就是3条线,我们相当于画3条线图。它的X轴表示的是阈值概率,Y轴表示的是净获益,可以看出算出净获益是关键,需要算出3个净获益,all,none,还有我们模型的净获益。
净获益是什么?
在这里插入图片描述
净获益需要算出真阳性人数和假阳性人数,所以我们需要算出一个关键的东西,就是预测概率,还有就是实际的结局,这样才能获取相关数据。下面我们通过一个例子来演示一下,通过文章《基于R语言做决策树和随机森林(2)》的数据作为例子,我们先导入数据和R包

library(randomForest)
library(pROC)
library(foreign)
bc <- read.spss("E:/r/test/bankloan_cs.sav",
                use.value.labels=F, to.data.frame=T)

删除部分多余的变量,得到如下数据
Age年龄, employ在职雇主的年限,address在这个地方住的时间,income收入,debtinc债务收入比,creddebt信用卡债务,othdebt其他债务,最后一个default是我们的结局指标,即是否是高风险客户。公众号回复:银行客户数据,可以获得该数据。

bc<-bc[,c(-1:-3,-13:-15,-5)]
head(bc,6)

##   age employ address income debtinc creddebt   othdebt default
## 1  28      7       2     44    17.7 2.990592  4.797408       0
## 2  64     34      17    116    14.7 5.047392 12.004608       0
## 3  40     20      12     61     4.8 1.042368  1.885632       0
## 4  30     11       3     27    34.5 1.751220  7.563780       0
## 5  25      2       2     30    22.4 0.759360  5.960640       1
## 6  35      2       9     38    10.9 1.462126  2.679874       1
bc$default<-as.factor(bc$default)

把数据分为训练集和预测集(就是一个建模,一个验证),要先设一个种子,这样有可重复性
###设置训练和预测集

set.seed(1)
index <- sample(2,nrow(bc),replace = TRUE,prob=c(0.7,0.3))
traindata <- bc[index==1,]
testdata <- bc[index==2,]

###拟合随机森林模型,默认的mtry的值是自变量除以3

def_ntree<- randomForest(default ~age+employ+address+income+debtinc+creddebt
                         +othdebt,data=traindata,
                         ntree=500,important=TRUE,proximity=TRUE)

使用验证集生成预测概率(我这里只是演示一下,你使用预测集也是可以的),这里def_pred生成了2个概率是0和1的概率,我们只需要1的概率,所以需要转化一下。

def_pred<-predict(def_ntree, newdata=testdata,type = "prob")##生成概率
def_pred<-as.data.frame(def_pred)
testdata$def_pred<-def_pred$`1`

我们先要生成验证集人数和算出实际发生结果的发生率,就是拿验证集的发生人数(就是1的部分)除以总人数,等下计算要用。

N=dim(testdata)[1]
testdata$default<-as.numeric(testdata$default)-1
event.rate=mean(testdata$default)

那未发生率就是

1-event.rate
## [1] 0.6391982

接下来我们要建一个净获益的预测数据表,到时会显示为X轴,范围肯定是0-1了,步长可以由我们自己设定,通常是0.01

nb=data.frame(threshold=seq(from=0, to=1, by=0.01))
head(nb,6)
##   threshold
## 1      0.00
## 2      0.01
## 3      0.02
## 4      0.03
## 5      0.04
## 6      0.05

根据净获益公式可以得到如下,这样nb就有3个数据了

nb["all"]=event.rate - (1-event.rate)*nb$threshold/(1-nb$threshold)
nb["none"]=0
head(nb,6)
##   threshold       all none
## 1      0.00 0.3608018    0
## 2      0.01 0.3543452    0
## 3      0.02 0.3477569    0
## 4      0.03 0.3410328    0
## 5      0.04 0.3341685    0
## 6      0.05 0.3271598    0

接下来就是算出真阳性和假阳性的人数(tp和fp),因为需要算的是不同预测下的真阳性和假阳性的人数(tp和fp),所以每个阈值都要跑一下,这里要写一个循环。tp等于数据中预测概率在大于阈值概率的部分的发生率,再乘以这部分的人数,fp刚好相反,体会一下。

for(t in 1:length(nb$threshold)){
    
    
  tp=mean(testdata[testdata["def_pred"]>=nb$threshold[t],"default"])*sum(testdata["def_pred"]>=nb$threshold[t])
  fp=(1-mean(testdata[testdata["def_pred"]>=nb$threshold[t],"default"]))*sum(testdata["def_pred"]>=nb$threshold[t])
  if (sum(testdata["def_pred"]>=nb$threshold[t])==0) {
    
    
    tp=0
    fp=0
  }
  nb[t,"def_pred"]=tp/N - fp/N*(nb$threshold[t]/(1-nb$threshold[t]))  #净获益公式
}

这样跑完循环后就得出了不同阈值下模型的净获益,就可以画图了

head(nb,6)
##   threshold       all none  def_pred
## 1      0.00 0.3608018    0 0.3608018
## 2      0.01 0.3543452    0 0.3546827
## 3      0.02 0.3477569    0 0.3487569
## 4      0.03 0.3410328    0 0.3433747
## 5      0.04 0.3341685    0 0.3376949
## 6      0.05 0.3271598    0 0.3323174

我们这里使用ggplot来画图,需要调整一下数据格式

library(reshape2)
library(ggplot2)

把长数据变成宽数据

plotdat <- melt(nb,id="threshold",measure=c("def_pred","all","none"))
head(plotdat,6)
##   threshold variable     value
## 1      0.00 def_pred 0.3608018
## 2      0.01 def_pred 0.3546827
## 3      0.02 def_pred 0.3487569
## 4      0.03 def_pred 0.3433747
## 5      0.04 def_pred 0.3376949
## 6      0.05 def_pred 0.3323174

绘制图形

ggplot(plotdat,aes(x=threshold,y=value,colour=variable))+geom_line()+
  coord_cartesian(xlim=c(0,1), ylim=c(-0.05,0.5))+ 
  labs(x="Threshold probability (%)")+labs(y="Net benefit")+
  scale_color_discrete(name="Model",labels=c("RF","all","none"))+
  theme_bw()+
  theme(panel.grid.major=element_blank(),
        panel.grid.minor=element_blank(),
        legend.title=element_blank())

在这里插入图片描述
这样图形就绘制好了,就几步,也是不难把,这个方法只要得出预测概率后,适用于各种模型包括lasso回归、机器学习等,其实和模型关系不大,主要是要算出预测概率,如果基础不好或者想图方便的朋友,也可以使用别人写好的函数,dca.r和stdca.r都可以.
我这里使用dca.r简单演示一下。
前面的步骤是一样的,一样要算出概率

set.seed(1)
index <- sample(2,nrow(bc),replace = TRUE,prob=c(0.7,0.3))
traindata <- bc[index==1,]
testdata <- bc[index==2,]

###拟合随机森林模型,默认的mtry的值是自变量除以3

def_ntree<- randomForest(default ~age+employ+address+income+debtinc+creddebt
                         +othdebt,data=traindata,
                         ntree=500,important=TRUE,proximity=TRUE)
def_pred<-predict(def_ntree, newdata=testdata,type = "prob")##生成概率
def_pred<-as.data.frame(def_pred)
testdata$def_pred<-def_pred$`1`

这里结局变量需转成数字,不然会报错。

testdata$default<-as.numeric(testdata$default)-1  ##这里结局变量需转成数字0和1

绘图,需要指定结局变量和预测概率,我们这里是结局是default,得到的预测概率是def_pred,

out<- dca(data = testdata, outcome = "default", 
                 predictors = c("def_pred"),
                 xstart = 0, xstop = 1, ymin = -0.05)

在这里插入图片描述
也可以把数据提取出来绘图

out$net.benefit
##     threshold           all none      def_pred
## 1        0.00   0.360801782    0  0.3608017817
## 2        0.01   0.354345234    0  0.3546826843
## 3        0.02   0.347756920    0  0.3487568747
## 4        0.03   0.341032765    0  0.3433747388

使用ggolot绘图上面已经演示过了,这里就不演示了。我把dca.r和stdca.r进行打包,需要这两个函数的请把公众号的本文章转发朋友圈集10个赞,截图发给我,嫌麻烦的给我打赏5元截图发给我也可以。

猜你喜欢

转载自blog.csdn.net/dege857/article/details/130592910