【问题标题】:Extract both training and testing AUROC from caret 10 fold CV从插入符号 10 倍 CV 中提取训练和测试 AUROC
【发布时间】:2018-06-16 07:06:03
【问题描述】:

假设我正在做如下分类:

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 值,那就太好了。

如何提取这些信息?我想确保我的模型没有过拟合(我使用的数据集非常小)。

谢谢!

【问题讨论】:

  • 这可行,但只报告验证集的 AUC(模型测试的 10%)。但是,如果将其他 90% 的训练数据放回模型中,我对 AUC 很感兴趣。知道该怎么做吗?
  • 仅供参考,对于我所做的子集:for (a in 1:length(model$bestTune)) { model$pred &lt;- model$pred[model$pred[, paste(colnames(model$bestTune)[a])] == model$bestTune[1, a], ] }
  • 训练集中的值不能用于你想要的目的。
  • @42- 你能详细说明一下吗?如果我没有单独的数据集进行验证,你会如何建议测试我的模型是否过拟合?进行 10 倍交叉验证是我正在使用的唯一“测试”集。
  • 我同意@42,对于像 xgboost 这样的模型,测试集折叠的 AUC 很可能是 1。这不会告诉你关于过度拟合的信息。显然它会过拟合,测试折叠上的值会告诉你过拟合的程度。关于主题,我不确定是否可以从插入符号训练对象中提取测试集错误,但如果您采用完全相同的折叠并制作自定义函数来执行 10 折 CV 并返回您的测试集指标,则可以轻松估计欲望。如果您对此感兴趣,我可以发布答案如何实现。

标签: r classification cross-validation r-caret xgboost


【解决方案1】:

根据 cmets 的要求,这里有一个自定义函数来评估交叉验证测试错误。我不确定它是否可以从插入符号火车对象中提取出来。

运行插入符号火车后,提取折叠以获得最佳曲调:

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

但我再次强调测试错误不会告诉你什么,你应该依赖训练错误。如果您想让两者更接近而不是考虑摆弄gammaalphalambda 参数。

对于一个小数据集,我仍然会尝试拆分 train : test = 80 : 20 并使用该独立测试集来验证 CV 误差是否接近测试误差。

【讨论】:

  • 如果独立测试集的测试误差与CV误差相似,那么模型没有过拟合,对吗?
  • @Keshav M 如果 CV 错误与测试错误相关,而不是模型运行良好。接近并不意味着什么,但是当 CV 误差越来越小时,测试误差也应该越来越小。如果没有,那就有问题了。
  • 对不起,我有点困惑。我在哪里得到多个 CV 错误和测试错误值来寻找相关性?我只是在考虑通过进行 CV 然后进行独立测试会产生的测试和 CV 错误的单个值。非常感谢您的帮助:)
  • @Keshav M 你正在测试一堆超参数,可能还有几个学习者。对于所有这些,您都可以生成 CV 错误和验证错误。虽然您不应该对所有测试用例都进行这些测试,因为它很可能会导致过度拟合(尤其是在小数据集上),但您可以选择几个,看看它们是否具有相同的趋势。验证误差是一个高度偏差的指标(取决于保留的样本,它可以返回非常不同的数字),而 CV 具有低偏差和低方差。然而 CV 经常被遗漏(分层、阻塞、过采样)。
猜你喜欢
  • 2021-01-22
  • 2020-10-13
  • 2021-08-11
  • 2018-02-06
  • 1970-01-01
  • 1970-01-01
  • 2012-07-06
  • 2018-01-02
  • 2015-12-30
相关资源
最近更新 更多