如何使用 R 中的 k 折 CV 每折手动训练数据?

How train data manually per fold with k-fold CV in R?

我有以下适合我的代码段,我得到了模型结果:

library(base)
library(caret)
library(tidyverse)

dataset <- read_csv("https://gist.githubusercontent.com/dmpe/bfe07a29c7fc1e3a70d0522956d8e4a9/raw/7ea71f7432302bb78e58348fede926142ade6992/pima-indians-diabetes.csv", col_names=FALSE)
X = dataset[, 1:8]
Y = as.factor(ifelse(dataset$X9 == 1, 'diabetes', 'nondiabetes'))

set.seed(88)

nfolds <- 3
cvIndex <- createFolds(Y, nfolds, returnTrain = T)

fit.control <- trainControl(method="cv",
                            index=cvIndex,
                            number=nfolds,
                            classProbs=TRUE,
                            savePredictions=TRUE,
                            verboseIter=TRUE,
                            summaryFunction=twoClassSummary,
                            allowParallel=FALSE)

model <- caret::train(X, Y,
                      method = "svmLinear",
                      trControl = fit.control,
                      preProcess=c("center","scale"),
                      tuneLength=10)

使用它我可以访问最终模型 model$finalModel,但是,在这种情况下,我实际上想要 3 个模型而不是一个最终模型,因为我有 3 倍。所以,我想在第一次折叠后得到经过训练的模型,然后是第二次折叠后,最后是第三次折叠后,这对应于实际的最终模型。任何想法如何在 R 中实现这一点?请注意 caret 的用法并不严格,如果您可以使用 mlr 也欢迎。

插入符号中的训练函数简化了模型评估和训练 https://cran.r-project.org/web/packages/caret/vignettes/caret.html

"使用重采样评估模型调整参数对性能的影响 在这些参数中选择“最佳”模型 从训练集中估计模型性能

所以,它给出的模型是最优的最终模型。 没有理由使用在每个折叠上训练的模型。我不知道如何在 R

中执行此操作

既不是插入符号也不是机器学习专家,但为什么不在随机样本上训练模型并将结果存储在列表中呢?

   data <- read_csv("https://gist.githubusercontent.com/dmpe/bfe07a29c7fc1e3a70d0522956d8e4a9/raw/7ea71f7432302bb78e58348fede926142ade6992/pima-indians-diabetes.csv", col_names=FALSE)

    train_multiple_models <- function(data, kfolds) {
        resultlist <- list()
        for(i in 1:kfolds) {

            sample <- sample.int(n = nrow(data), size = floor(.75*nrow(data)), replace = F)
            train <- data[sample, ]

            X = train[, 1:8]
            Y = as.factor(ifelse(train$X9 == 1, 'diabetes', 'nondiabetes'))

            model <- caret::train(X, Y,
                                  method = "svmLinear",
                                  preProcess=c("center","scale"),
                                  tuneLength=10)
            resultlist[[i]] <- model
        }
        return(resultlist)
    }

    result <- train_multiple_models(data, kfolds = 3)


    > result[[1]]$finalModel
    Support Vector Machine object of class "ksvm" 

    SV type: C-svc  (classification) 
     parameter : cost C = 1 

    Linear (vanilla) kernel function. 

    Number of Support Vectors : 307 

    Objective Function Value : -302.065 
    Training error : 0.230903 

这里有一个使用 mlr 包的方法:

library(mlr)
library(base)
library(tidyverse)

dataset <- read_csv("https://gist.githubusercontent.com/dmpe/bfe07a29c7fc1e3a70d0522956d8e4a9/raw/7ea71f7432302bb78e58348fede926142ade6992/pima-indians-diabetes.csv", col_names=FALSE)
X = dataset[, 1:8]
Y = as.factor(ifelse(dataset$X9 == 1, 'diabetes', 'nondiabetes'))

创建一个 mlr 任务:

mlr_task <-  makeClassifTask(data = data.frame(X, Y),
                             target = "Y",
                             positive = "diabetes")

定义重采样:

set.seed(7)

cv3 <- makeResampleInstance(makeResampleDesc("CV", iters = 3),
                            task = mlr_task)

定义超参数搜索的类型

ctrl <- makeTuneControlRandom(maxit = 10L)

定义学习者

lrn <- makeLearner("classif.ksvm", predict.type = "prob")

可选地检查学习者参数以查看要调整的参数

mlr::getLearnerParamSet(lrn)

定义搜索space(vanilladot 是 kernlab 包中的线性内核,在内部为 "classif.ksvm" 调用)。有关 mlr 中集成学习器的更多信息:https://mlr.mlr-org.com/articles/tutorial/integrated_learners.html

ps <- makeParamSet(makeDiscreteParam("kernel", "vanilladot"),
                   makeNumericParam("C", lower = 2e-6, upper = 2e-6))

调整超参数。我只是设置了一些随机的措施,列出的第一个用于评估性能,其他的只是为了展示。

res <- tuneParams(lrn,
                  mlr_task,
                  cv3,
                  measures = list(auc, bac, f1),
                  par.set = ps,
                  control = ctrl)

为学习者设置最佳超参数

lrn <- setHyperPars(lrn, par.vals = res$x)

使用 models = TRUE

重新采样
rsmpls <- resample(lrn,
                   mlr_task,
                   cv3,
                   measures = list(auc, bac, f1),
                   models = TRUE)

模型在

rsmpls$models[[1]]$learner.model  
rsmpls$models[[2]]$learner.model  
rsmpls$models[[3]]$learner.model  

它的作用是首先调整超参数,然后在相同的折叠上使用调整后的参数执行另一组交叉验证。

一种替代方法,在我看来,一种更好的方法是在嵌套交叉验证的内部折叠中选择超参数,并在外部折叠上进行评估,使外部折叠模型保持 fiddle with.

lrn <- makeLearner("classif.ksvm", predict.type = "prob")

定义内部重采样策略

cv3_inner <- makeResampleDesc("CV", iters = 3)

创建一个 tune wrapper - 定义内部交叉验证循环中发生的事情

lrn <- makeTuneWrapper(lrn,
                       resampling = cv3_inner,
                       measures = list(auc, bac, f1),
                       par.set = ps,
                       control = ctrl)

执行外部交叉验证

rsmpls <- resample(lrn,
                   mlr_task,
                   cv3,
                   measures = list(auc, bac, f1),
                   models = TRUE)

这在外循环中执行三重 CV,在每个训练实例中,另一个,执行三重 CV 以调整超参数,并使用最佳超参数在整个训练实例上拟合模型,评估这些模型在外循环测试实例上。这样做是为了减少评估偏差。另见:https://mlr.mlr-org.com/articles/tutorial/nested_resampling.html