从 caret 10 fold CV 中提取训练和测试 AUROC
Extract both training and testing AUROC from caret 10 fold CV
假设我正在做如下分类:
library(mlbench)
data(Sonar)
library(caret)
set.seed(998)
my_data <- Sonar
fitControl <-
trainControl(
method = "cv",
number = 10,
classProbs = T,
savePredictions = T,
summaryFunction = twoClassSummary
)
model <- train(
Class ~ .,
data = my_data,
method = "xgbTree",
trControl = fitControl,
metric = "ROC"
)
对于 10 折中的每一折,10% 的数据用于验证。对于插入符号确定的最佳参数,我可以使用 getTrainPerf(model)
找到所有 10 折的平均验证 AUC 或 model$resample
以获得每个折的 AUC 的单个值。但是,如果将训练数据放回同一个模型,我将无法获得 AUC。如果我能获得每个训练集的单独 AUC 值,那就太好了。
如何提取这些信息?我想确保我的模型没有过度拟合(我使用的数据集非常小)。
谢谢!
这里的评论中要求的是一个自定义函数来评估交叉验证测试错误。我不确定是否可以从 caret train 对象中提取它。
在 运行 之后,插入符序列提取最佳音调的褶皱:
library(tidyverse)
model$bestTune %>%
left_join(model$pred) %>%
select(rowIndex, Resample) %>%
mutate(Resample = as.numeric(gsub(".*(\d$)", "\1", Resample)),
Resample = ifelse(Resample == 0, 10, Resample)) %>%
arrange(rowIndex) -> resamples
构造一个交叉验证函数,它将使用与插入符号相同的折叠:
library(xgboost)
train <- my_data[,!names(my_data)%in% "Class"]
label <- as.numeric(my_data$Class) - 1
test_auc <- lapply(1:10, function(x){
model <- xgboost(data = data.matrix(train[resamples[,2] != x,]),
label = label[resamples[,2] != x],
nrounds = model$bestTune$nrounds,
max_depth = model$bestTune$max_depth,
gamma = model$bestTune$gamma,
colsample_bytree = model$bestTune$colsample_bytree,
objective = "binary:logistic",
eval_metric= "auc" ,
print_every_n = 50)
preds_train <- predict(model, data.matrix(train[resamples[,2] != x,]))
preds_test <- predict(model, data.matrix(train[resamples[,2] == x,]))
auc_train <- pROC::auc(pROC::roc(response = label[resamples[,2] != x], predictor = preds_train, levels = c(0, 1)))
auc_test <- pROC::auc(pROC::roc(response = label[resamples[,2] == x], predictor = preds_test, levels = c(0, 1)))
return(data.frame(fold = unique(resamples[resamples[,2] == x, 2]), auc_train, auc_test))
})
do.call(rbind, test_auc)
#output
fold auc_train auc_test
1 1 1 0.9909091
2 2 1 0.9797980
3 3 1 0.9090909
4 4 1 0.9629630
5 5 1 0.9363636
6 6 1 0.9363636
7 7 1 0.9181818
8 8 1 0.9636364
9 9 1 0.9818182
10 10 1 0.8888889
arrange(model$resample, Resample)
#output
ROC Sens Spec Resample
1 0.9909091 1.0000000 0.8000000 Fold01
2 0.9898990 0.9090909 0.8888889 Fold02
3 0.9909091 0.9090909 1.0000000 Fold03
4 0.9444444 0.8333333 0.8888889 Fold04
5 0.9545455 0.9090909 0.8000000 Fold05
6 0.9272727 1.0000000 0.7000000 Fold06
7 0.9181818 0.9090909 0.9000000 Fold07
8 0.9454545 0.9090909 0.8000000 Fold08
9 0.9909091 0.9090909 0.9000000 Fold09
10 0.8888889 0.9090909 0.7777778 Fold10
为什么我的函数和插入符号的测试折叠 AUC 不一样我不能说。我相当确定使用了相同的参数和折叠。我可以假设它与随机种子有关。当我检查插入符号测试预测的 auc 时,我得到与插入符号相同的输出:
model$bestTune %>%
left_join(model$pred) %>%
arrange(rowIndex) %>%
select(M, Resample, obs) %>%
mutate(Resample = as.numeric(gsub(".*(\d$)", "\1", Resample)),
Resample = ifelse(Resample == 0, 10, Resample),
obs = as.numeric(obs) - 1) %>%
group_by(Resample) %>%
do(auc = as.vector(pROC::auc(pROC::roc(response = .$obs, predictor = .$M)))) %>%
unnest()
#output
Resample auc
<dbl> <dbl>
1 1.00 0.991
2 2.00 0.990
3 3.00 0.991
4 4.00 0.944
5 5.00 0.955
6 6.00 0.927
7 7.00 0.918
8 8.00 0.945
9 9.00 0.991
10 10.0 0.889
但我再次强调测试误差不会告诉你什么,你应该依赖训练误差。如果你想让两者更接近而不是考虑摆弄 gamma
、alpha
和 lambda
参数。
对于小数据集,我仍然会尝试拆分 train : test = 80 : 20 并使用该独立测试集来验证 CV 误差是否接近测试误差。
假设我正在做如下分类:
library(mlbench)
data(Sonar)
library(caret)
set.seed(998)
my_data <- Sonar
fitControl <-
trainControl(
method = "cv",
number = 10,
classProbs = T,
savePredictions = T,
summaryFunction = twoClassSummary
)
model <- train(
Class ~ .,
data = my_data,
method = "xgbTree",
trControl = fitControl,
metric = "ROC"
)
对于 10 折中的每一折,10% 的数据用于验证。对于插入符号确定的最佳参数,我可以使用 getTrainPerf(model)
找到所有 10 折的平均验证 AUC 或 model$resample
以获得每个折的 AUC 的单个值。但是,如果将训练数据放回同一个模型,我将无法获得 AUC。如果我能获得每个训练集的单独 AUC 值,那就太好了。
如何提取这些信息?我想确保我的模型没有过度拟合(我使用的数据集非常小)。
谢谢!
这里的评论中要求的是一个自定义函数来评估交叉验证测试错误。我不确定是否可以从 caret train 对象中提取它。
在 运行 之后,插入符序列提取最佳音调的褶皱:
library(tidyverse)
model$bestTune %>%
left_join(model$pred) %>%
select(rowIndex, Resample) %>%
mutate(Resample = as.numeric(gsub(".*(\d$)", "\1", Resample)),
Resample = ifelse(Resample == 0, 10, Resample)) %>%
arrange(rowIndex) -> resamples
构造一个交叉验证函数,它将使用与插入符号相同的折叠:
library(xgboost)
train <- my_data[,!names(my_data)%in% "Class"]
label <- as.numeric(my_data$Class) - 1
test_auc <- lapply(1:10, function(x){
model <- xgboost(data = data.matrix(train[resamples[,2] != x,]),
label = label[resamples[,2] != x],
nrounds = model$bestTune$nrounds,
max_depth = model$bestTune$max_depth,
gamma = model$bestTune$gamma,
colsample_bytree = model$bestTune$colsample_bytree,
objective = "binary:logistic",
eval_metric= "auc" ,
print_every_n = 50)
preds_train <- predict(model, data.matrix(train[resamples[,2] != x,]))
preds_test <- predict(model, data.matrix(train[resamples[,2] == x,]))
auc_train <- pROC::auc(pROC::roc(response = label[resamples[,2] != x], predictor = preds_train, levels = c(0, 1)))
auc_test <- pROC::auc(pROC::roc(response = label[resamples[,2] == x], predictor = preds_test, levels = c(0, 1)))
return(data.frame(fold = unique(resamples[resamples[,2] == x, 2]), auc_train, auc_test))
})
do.call(rbind, test_auc)
#output
fold auc_train auc_test
1 1 1 0.9909091
2 2 1 0.9797980
3 3 1 0.9090909
4 4 1 0.9629630
5 5 1 0.9363636
6 6 1 0.9363636
7 7 1 0.9181818
8 8 1 0.9636364
9 9 1 0.9818182
10 10 1 0.8888889
arrange(model$resample, Resample)
#output
ROC Sens Spec Resample
1 0.9909091 1.0000000 0.8000000 Fold01
2 0.9898990 0.9090909 0.8888889 Fold02
3 0.9909091 0.9090909 1.0000000 Fold03
4 0.9444444 0.8333333 0.8888889 Fold04
5 0.9545455 0.9090909 0.8000000 Fold05
6 0.9272727 1.0000000 0.7000000 Fold06
7 0.9181818 0.9090909 0.9000000 Fold07
8 0.9454545 0.9090909 0.8000000 Fold08
9 0.9909091 0.9090909 0.9000000 Fold09
10 0.8888889 0.9090909 0.7777778 Fold10
为什么我的函数和插入符号的测试折叠 AUC 不一样我不能说。我相当确定使用了相同的参数和折叠。我可以假设它与随机种子有关。当我检查插入符号测试预测的 auc 时,我得到与插入符号相同的输出:
model$bestTune %>%
left_join(model$pred) %>%
arrange(rowIndex) %>%
select(M, Resample, obs) %>%
mutate(Resample = as.numeric(gsub(".*(\d$)", "\1", Resample)),
Resample = ifelse(Resample == 0, 10, Resample),
obs = as.numeric(obs) - 1) %>%
group_by(Resample) %>%
do(auc = as.vector(pROC::auc(pROC::roc(response = .$obs, predictor = .$M)))) %>%
unnest()
#output
Resample auc
<dbl> <dbl>
1 1.00 0.991
2 2.00 0.990
3 3.00 0.991
4 4.00 0.944
5 5.00 0.955
6 6.00 0.927
7 7.00 0.918
8 8.00 0.945
9 9.00 0.991
10 10.0 0.889
但我再次强调测试误差不会告诉你什么,你应该依赖训练误差。如果你想让两者更接近而不是考虑摆弄 gamma
、alpha
和 lambda
参数。
对于小数据集,我仍然会尝试拆分 train : test = 80 : 20 并使用该独立测试集来验证 CV 误差是否接近测试误差。