欢迎大家关注我的公众号:一只勤奋的科研喵
目 录
- K折交叉验证简介
- R语言N次K折交叉验证
- 不同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折交叉验证。这样做出的结果可能会更加准确。
如文献所示:
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-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]],]
- 可以发现,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)
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. 不同交叉验证比较
结果
- 无交叉验证AUC值:0.906
- 400次5折交叉验证平均AUC :0.89047
- 200次10折交叉验证平均AUC:0.89092
- 单纯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折交叉验证