【问题标题】:Extracting predictions from caret's train function从插入符号的训练函数中提取预测
【发布时间】:2021-01-22 17:37:47
【问题描述】:

我正在尝试重现 missuse 的工作 answer 以从插入符号的 train 函数中提取预测。我正在使用弹性网,但无法获得它。

这是一个可重现的例子:

require(caret)   
require(glmnet)

x = matrix(rnorm(100 * 20), 100, 20)   
set.seed(3) 
g = sample(c(0,1), 100, replace = TRUE)

df = as.data.frame(x) 
g_f = as.factor(g) 
df$g_f = g_f

train_control <- trainControl(   
method="cv",    
number = 3,    
savePredictions = T)

sorozat = seq(0, 1, 0.25)

search_grid <- expand.grid(   
alpha = sorozat,    
lambda = sorozat )

set.seed(3) 
fit2 <- train(g_f ~ .,    
data = df,    
trControl = train_control,    
tuneGrid = search_grid,   
preProc = c("BoxCox", "center", "scale"),   
method = "glmnet")

而我的尝试却报错:

prediction2 <- predict(fit2$finalModel,
                       data = predict(fit2$preProcess,
                                      df))$prediction

predict.glmnet(fit2$finalModel, data = predict(fit2, df)) 中的错误: 您需要为“newx”提供一个值

以下是我如何获得预测。但是如果它的混淆矩阵,我怎么能确定它是否是正确的:

# CM ver.1
pred_f = predict(fit2, df)
cm = as.data.frame(pred_f)
cm$g = g_f
table(cm)
      g
pred_f  0  1
     0 29  9
     1 15 47

与模型提供的不同?

# CM ver.2
confusionMatrix(fit2)$table
          Reference
Prediction  0  1
         0 23 16
         1 21 40

提前感谢您的帮助!

编辑:添加混淆矩阵的输出。

【问题讨论】:

  • 感谢您的通知!我更正了它,但错误仍然存​​在

标签: r r-caret glmnet


【解决方案1】:

链接的答案不适用于 glmnet,因为 predict.glmnet 有一些特殊性:

predict.glmnet 的数据参数称为newx,并且必须是矩阵。

除此之外,这个预测函数使用所有拟合的 lambda 来创建预测,所以如果你想要最好的,你必须这样指定。此外,建议设置对链接的响应:

使用您的示例,最佳拟合值为 alpha = 0.5 和 lambda = 0.25。 alpha 在模型内部设置,但 lambda 必须在预测期间指定。

但首先我们必须预处理测试数据(与链接答案相同):

predict(fit2$preProcess, df)

然而,这会返回一个带有类列的数据框,因此为了将其提供给predict.glmnet,必须删除响应列(因子)并将数据框转换为矩阵:

as.matrix(predict(fit2$preProcess, df)[,-21])

现在调用predict.glmnet,最佳 lambda 为 0.25,将预测类型设置为类:

library(glmnet)
prediction2 <- predict(fit2$finalModel,
                       newx = as.matrix(predict(fit2$preProcess,
                                      df)[,-21]),
                       type = "class",
                       s = 0.25)

head(prediction2)
     1  
[1,] "0"
[2,] "1"
[3,] "0"
[4,] "0"
[5,] "0"
[6,] "0"

编辑:回答有关混淆矩阵差异的已编辑问题。

当您在train 的输出上调用confusionMatrix 时,结果矩阵是从重采样期间的非折叠预测中获得的 - 因为这些是测试集预测,所以偏差较小。

当您在所有数据(这是fit2$finalModel)上拟合模型并使用它来预测您正在创建训练集预测的相同数据时 - 由于模型是使用这些观察结果拟合的,因此存在很大偏差。这就是在这种情况下,与在fit2 上调用confusionMatrix 相比,非对角线总和要少得多的原因。这有时被称为过度拟合——模型对它已经看到的数据的预测要好得多。

总之

`confusionMatrix(fit2)`

从不折叠的预测中产生一个混淆矩阵。这可以作为模型选择的指标。

同时

confusionMatrix(as.factor(prediction2), g_f)

根据对训练数据的模型预测生成高度偏差的混淆矩阵。这不应用作模型选择的指标。

EDTI2:我突然想到这可能是XY problem

如果您只想要交叉验证的预测,您可以简单地使用:

fit2$pred

如果你想计算这些的 AUC,你应该在 trainControl 中指定你想要的类概率:

train_control <- trainControl(   
  method="cv",    
  number = 3,    
  savePredictions = TRUE,
  classProbs = TRUE)

另一个问题是类级别必须是有效的变量名称,因此 0 和 1 等数字不起作用,一个简单的解决方法是:

df$g_f <- factor(df$g_f,
                 levels = c(0, 1),
                 labels = c("zero", "one"))

合体后:

set.seed(3) 
fit2 <- train(g_f ~ .,    
              data = df,    
              trControl = train_control,    
              tuneGrid = search_grid,   
              preProc = c("BoxCox", "center", "scale"),   
              method = "glmnet")

预测在fit2$pred:

head(fit2$pred)
#output
  pred  obs rowIndex      zero       one alpha lambda Resample
1  one  one        2 0.4513397 0.5486603     0      1    Fold1
2 zero zero        4 0.5764889 0.4235111     0      1    Fold1
3 zero  one        5 0.5154925 0.4845075     0      1    Fold1
4  one  one        6 0.4836418 0.5163582     0      1    Fold1
5 zero zero        7 0.5199623 0.4800377     0      1    Fold1
6  one zero        8 0.4770536 0.5229464     0      1    Fold1

这些预测适用于所有经过测试的超参数组合,以获取性能最佳的超参数:

library(tidyverse)

fit2$pred %>%
  filter(alpha == fit2$bestTune$alpha&
         lambda == fit2$bestTune$alpha) -> best_preds

有两种方法可以从这些预测中获取指标。

方法 1。您可以使用组合折叠预测来做到这一点(当您拥有较小的数据集时频率较低但很有用,因此折叠性能存在很大差异)

pROC::roc(best_preds$obs, best_preds$one)$auc
#output
Area under the curve: 0.6631

方法 2。您可以按折叠和平均计算它(更常见,并且插入符号在内部用于任何指标:

library(tidyverse)

best_preds %>%
  group_by(Resample) %>%
  summarise(auc = as.numeric(pROC::roc(obs, one)$auc))
#output
  Resample   auc
  <chr>    <dbl>
1 Fold1    0.592
2 Fold2    0.757
3 Fold3    0.614

以上是每折的AUC

平均:

best_preds %>%
  group_by(Resample) %>%
  summarise(auc = as.numeric(pROC::roc(obs, one)$auc)) %>%
  ungroup() %>%
  summarise(mean_auc = mean(auc))
#output
  mean_auc
     <dbl>
1    0.654

【讨论】:

  • 非常感谢您的清晰解释。它确实有效并产生与predict(fit2, df) 相同的结果。您能否顺便评论一下为什么两个混淆矩阵的结果之间存在差异?
  • 不鼓励在收到答案后使用新问题编辑问题。 When you get a satisfactory answer to a question you should accept it。如果出现其他问题,请发布新问题。在这种情况下,我将编辑我的答案以反映问题的变化。
  • 我很抱歉一开始没有说这个,但我发布这个问题是为了能够从预测中计算 AUC。我意识到我原来的帖子中实际上有两个问题。尽管如此,你确实帮助我找到了答案。我意识到dat = fit2$pred 的乘积是一个数据框,我可以从中提取属于最佳模型的响应,如下所示:dat_s = dat[(dat$alpha == 0 &amp; dat$lambda == 0.25),] 那么正确的混淆矩阵就是:table(dat_s$pred, dat_s$obs) 感谢您的耐心等待!
  • 要从交叉验证的预测中计算 AUC,请将参数 summaryFunction = twoClassSummary 添加到 train_control。这样,您将使用 AUC 进行模型选择。如果您打算使用插入符号 Max Kuhn book 是必须阅读的
  • 我刚刚想到这可能是一个 XY 问题。见 EDIT2
猜你喜欢
  • 2018-06-16
  • 2019-09-06
  • 2020-10-13
  • 2021-08-11
  • 2018-11-05
  • 2018-02-06
  • 1970-01-01
  • 2011-09-19
  • 1970-01-01
相关资源
最近更新 更多