R语言 | N次K折交叉验证(基于逻辑回归)

欢迎大家关注我的公众号:一只勤奋的科研喵

N次K折交叉验证

目 录

  1. K折交叉验证简介
  2. R语言N次K折交叉验证
  3. 不同K取值的比较

1. 交叉验证基本介绍

通常在建立模型后需要使用外部进行验证,以评估模型的外部可用性。然而,获取外部数据并不容易,这时交叉验证(Cross Validation)则是一种较好的可替代方案。交叉验证的方法很多,这里我们介绍最常用的k折交叉验证

简单解释一下:
  • 假如原始数据为100例患者,建模后我们使用K折交叉验证(K一般取3-10折)。
  • 若取K=10,则:将原始数据分为10份(K值):
  • 9份做训练,1份做验证,这样循环10次(因为这样的组合有10种)。
  • 取10次评价指标的平均值(如AUC值)作为模型的验证结果。

即【数据分为K个子集,1个子集做验证,K-1个子集做训练,这样的取法有K种,所以会产生K个新数据集(训练集+训练集)。我们进行K次训练和验证得到的平均评价指标可能较为准确


为了保证数据分割的影响,目前的k折交叉验证一般会进行多次重复(200-1000次)。即进行200次的10折交叉验证。这样做出的结果可能会更加准确。
如文献所示:

参考文献:Alexia Iasono et al. How To Build and Interpret a Nomogram for Cancer Prognosis.png

参考文献:Development and validation of NTCP models for acute side-effects resulting from proton beam therapy of brain tumours.png

2. R语言:K折交叉验证

1.载入R包和数据

library(caret)#做交叉验证用
library(pROC)#画ROC曲线用
#清理运行环境
rm(list = ls()) 
#载入R包
aa<- read.csv('交叉验证示例.csv')
#查看变量性质
str(aa)
#批量数值转因子
for (i in names(aa)[c(4:9)]){aa[,i] <- as.factor(aa[,i])}
#再次检查变量性质
str(aa)
  • 载入数据后查看数据类型、有无缺项等是做数据分析很重要的一步,很大一部分错误都是原始数据转换出错造成的。
  • 分类变量是factor形式而不是num/int
    2.png

2-1 数据分割(K折)

#设置随机种子,使数据分割可重复
set.seed(1)
#多次K折交叉验证,如5折400次交叉验证
folds <-createMultiFolds(y=aa$status,k=5,times=400)
#folds会产生5*400=2000个数据组合
#取fold 1数据为训练集,
train <- aa[folds[[1]],]
#其余为验证集
test <- aa[-folds[[1]],]
3.png
  • 可以发现,Rstudio右边生成了2000个数据集是5折交叉验证重复的400次。
  • 训练集310或311人,满足K-1组人做训练,1组做验证

2-2 取1个数据集做一次训练和验证

#构建逻辑回归模型
model<-glm(status~age+n+hr+lvi+g+rt,
          family = binomial(link=logit), 
          data=train )
#验证队列做预测
model_pre<-predict(model,
                   type='response',
                   newdata=test)
#查看AUC值、敏感性、特异性
roc1<-roc((test$status),model_pre)
round(auc(roc1),3)
roc1$sensitivities
round(roc1$specificities,3)
#ROC可视化
plot(roc1, 
     print.auc=T, 
     auc.polygon=T, 
     auc.polygon.col="skyblue",
     grid=c(0.1, 0.2),
     grid.col=c("green", "red"), 
     max.auc.polygon=T,
     print.thres=T)

4.png

2-3 批量计算AUC值

上述过程重复2000次,得到2000个auc值,取平均值即可得到模型400次5折交叉验证的auc校准值。

#建一个放auc值的空向量
auc_value<-as.numeric()
#上述步骤2000次
for(i in 1:2000){
  train<- aa[ folds[[i]],] #folds[[i]]作为测试集
  test <- aa[-folds[[i]],] #剩下的数据作为训练集
  model<- glm(status~age+n+hr+lvi+g+rt,family=binomial(link=logit),data=train)
  model_pre<-predict(model,type='response', newdata=test)
  auc_value<- append(auc_value,as.numeric(auc(as.numeric(test[,1]),model_pre)))
}
#查看auc值分及平均auc
summary(auc_value)
mean(auc_value) 
# AUC=0.8901765



3. 不同交叉验证比较

结果

    1. 无交叉验证AUC值:0.906
    1. 400次5折交叉验证平均AUC :0.89047
    1. 200次10折交叉验证平均AUC:0.89092
    1. 单纯10折交叉验证平均AUC :0.88537
      因此交叉验证是十分必要的,推荐N次K折交叉验证

1. 400次5折交叉验证
平均AUC=0.890468(代码见上)
2. 不做交叉验证
AUC=0.906

model1<-glm(status~age+n+hr+lvi+g+rt,
            family = binomial(link = logit),
            data=aa)
model_pre1<-predict(model1,type='response')
roc2<-roc((aa$status),model_pre1);auc(roc2)

3. 200次10折交叉验证
平均AUC=0.8909152

set.seed(1)
folds <-createMultiFolds(y=aa$status,k=10,times=200)
#2000次批量训练与验证
#做成循环
auc_value<-as.numeric()
for(i in 1:2000){
  train<- aa[ folds[[i]],] 
  test <- aa[-folds[[i]],] 
  model<- glm(status~age+n+hr+lvi+g+rt,family=binomial(link=logit),data=train)
  model_pre<-predict(model,type='response', newdata=test)
  auc_value<- append(auc_value,as.numeric(auc(as.numeric(test[,1]),model_pre)))
}
mean(auc_value)

4. 单纯10折交叉验证
平均AUC=0.8853679

set.seed(1)
#单纯10折交叉验证,time=1
folds <-createMultiFolds(y=aa$status,k=10,times=1)
#10次批量训练与验证
#做成循环
auc_value<-as.numeric()
for(i in 1:10){
  train<- aa[ folds[[i]],] 
  test <- aa[-folds[[i]],] 
  model<- glm(status~age+n+hr+lvi+g+rt,
              family=binomial(link=logit),data=train)
  model_pre<-predict(model,type='response', newdata=test)
  auc_value<- append(auc_value,
                     as.numeric(auc(as.numeric(test[,1]),model_pre)))
}
mean(auc_value)

欢迎大家关注我的公众号:一只勤奋的科研喵

相关专题:

  • R语言 | X年N次K折交叉验证
  • R语言 | 多指标N次K折交叉验证
一只勤奋的科研喵

你可能感兴趣的:(R语言 | N次K折交叉验证(基于逻辑回归))