使用caret包和R绘制学习曲线

9

我想研究模型调优中偏差/方差的最佳折衷。我正在使用R的caret库,它允许我绘制性能指标(AUC、准确性等)与模型的超参数(mtry、lambda等)之间的图,并自动选择最大值。这通常会返回一个好的模型,但如果我想进一步挖掘并选择不同的偏差/方差折衷,我需要一个学习曲线,而不是性能曲线。

为了简单起见,假设我的模型是随机森林,只有一个超参数'mtry'

我想绘制训练集和测试集的学习曲线。类似下面这样:

learning curve

(红色曲线是测试集)

在y轴上放置一个误差度量(错误分类的示例数量或类似的内容); 在x轴上放置'mtry'或者替代方法是训练集大小。

问题:

  1. caret是否具有迭代训练不同大小的训练集折叠的功能?如果我必须手动编码,我该怎么做?

  2. 如果我想将超参数放在x轴上,我需要通过caret::train训练所有模型,而不仅仅是最终模型(经过CV后表现最佳的模型)。这些“丢弃”的模型在train之后是否仍然可用?


请参见:http://topepo.github.io/caret/model-training-and-tuning.html#plotting-the-resampling-profile - Brian D
3个回答

4
这是我处理在使用 Caret 包训练模型时,如何在 R 中绘制学习曲线的方法。 我在 R 中使用 Motor Trend Car Road Tests 数据集进行说明。首先,我将mtcars数据集随机划分为训练集和测试集。用于训练的记录有21条,测试集有13条。在本例中,响应特征是 mpg。请注意保留 HTML 标记。
# set seed for reproducibility
set.seed(7)

# randomize mtcars
mtcars <- mtcars[sample(nrow(mtcars)),]

# split iris data into training and test sets
mtcarsIndex <- createDataPartition(mtcars$mpg, p = .625, list = F)
mtcarsTrain <- mtcars[mtcarsIndex,]
mtcarsTest <- mtcars[-mtcarsIndex,]

# create empty data frame 
learnCurve <- data.frame(m = integer(21),
                     trainRMSE = integer(21),
                     cvRMSE = integer(21))

# test data response feature
testY <- mtcarsTest$mpg

# Run algorithms using 10-fold cross validation with 3 repeats
trainControl <- trainControl(method="repeatedcv", number=10, repeats=3)
metric <- "RMSE"

# loop over training examples
for (i in 3:21) {
    learnCurve$m[i] <- i
    
    # train learning algorithm with size i
    fit.lm <- train(mpg~., data=mtcarsTrain[1:i,], method="lm", metric=metric,
             preProc=c("center", "scale"), trControl=trainControl)        
    learnCurve$trainRMSE[i] <- fit.lm$results$RMSE
    
    # use trained parameters to predict on test data
    prediction <- predict(fit.lm, newdata = mtcarsTest[,-1])
    rmse <- postResample(prediction, testY)
    learnCurve$cvRMSE[i] <- rmse[1]
}

pdf("LinearRegressionLearningCurve.pdf", width = 7, height = 7, pointsize=12)

# plot learning curves of training set size vs. error measure
# for training set and test set
plot(log(learnCurve$trainRMSE),type = "o",col = "red", xlab = "Training set size",
          ylab = "Error (RMSE)", main = "Linear Model Learning Curve")
lines(log(learnCurve$cvRMSE), type = "o", col = "blue")
legend('topright', c("Train error", "Test error"), lty = c(1,1), lwd = c(2.5, 2.5),
       col = c("red", "blue"))

dev.off()

输出的图如下所示:
enter image description here

1
谢谢!!这正是我在寻找的。 - programandoconro

4
  1. 如果你设置了trainControl()函数和参数(如mtry),并使用tuneGrid(),则Caret将为您迭代地测试许多交叉验证模型。这两个参数将作为控制选项传递给train()函数。tuneGrid参数的具体细节(如mtry、ntree)将因模型类型而异。

  2. 是的,最终的trainFit模型将包含您的CV所有折叠的错误率(以您指定的方式)。

因此,您可以指定例如10倍交叉验证和一个具有10个mtry值的网格-这将是100次迭代。您可能需要喝杯茶或午餐。

如果这听起来很复杂... 这里有一个非常好的例子-Caret是有关文档记录最好的软件包之一。


1
谢谢您的回答,但我仍然有疑问。我需要的不是在不同的CV(boostrap等)折叠上进行迭代训练,而是使用训练集的不同子集(10%,20%... 100%)模拟整个train()过程(包括CV等)。基本上,我想要估计更多的训练集大小是否会减少我的高方差。对于第二个问题,我需要变化超参数mtry的错误率,但如果我理解您的意思,trainFit将计算不同CV折叠的错误率(最终的错误率是所有错误率的平均值,我想)。 - Gabriele B
如果您想进行预训练分割,则可以使用createDataPartition创建几个不同的平衡训练集,例如train10、train20、train100,然后在每个训练集上使用tuneGrid选项矩阵运行train。您甚至可能需要使用一些不同的抽样重复train10a、train10b、train10c等。 - Stephen Henderson
1
据我所知,使用tuneGrid可以指定要测试的每个超参数的范围。这很好。然后,我将使用createDataPartition预先拆分数据,并使用循环(或类似的东西)调用train() n次。因此,只需要解决最后一个问题:如何获取不同参数的错误率? - Gabriele B
@StephenHenderson 链接失效了。我相信你所指的是由Max Kuhn编写的Caret软件包文档中的这个部分模型训练和调整 - Ekaba Bisong
@EkabaBisong 谢谢,我已经编辑了原始答案,使用了你建议的新链接。 - Stephen Henderson

2
在某个时间点,可能是在提出这个问题之后,caret软件包添加了learning_curve_dat函数,该函数有助于评估模型在一系列训练集大小下的性能。
以下是该函数文档中的示例:
library(caret)
set.seed(1412)
class_dat <- twoClassSim(1000)

set.seed(29510)
lda_data <- learning_curve_dat(dat = class_dat, 
                               outcome = "Class",
                               test_prop = 1/4, 
                               ## `train` arguments:
                               method = "lda", 
                               metric = "ROC",
                               trControl = trainControl(classProbs = TRUE, 
                                                        summaryFunction = twoClassSummary))

ggplot(lda_data, aes(x = Training_Size, y = ROC, color = Data)) + 
  geom_smooth(method = loess, span = .8)

每个Training_Size都可以找到性能指标,并将其保存在lda_data中,同时还保存了Data变量(“Resampling”,“Training”和可选的“Testing”)。
这里是函数文档的链接:https://rdrr.io/cran/caret/man/learning_curve_dat.html 需要明确的是,这回答了问题的第一部分,但没有回答第二部分。
注意,在至少2020年8月之前,caret包的代码和文档中存在一个拼写错误。函数调用为“learing_curve_dat”,然后才更正为“learning_curve_dat”。我已经更新了我的答案以反映这个更改。请确保您正在使用最新版本的caret包。

2
我一直在琢磨为什么这个函数不起作用,后来发现caret包中有一个错别字,它被拼写成了learing_curve_dat()而不是learning_curve_dat() - gofraidh
好的发现!我已经更新了我的答案。感谢您的评论。 - makeyourownmaker
1
拼写错误现在已经修正。 - Simon Woodward
1
@SimonWoodward 感谢您对 learning_curve_dat 拼写修正的更新。 - makeyourownmaker

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接