【问题标题】:How train data manually per fold with k-fold CV in R?如何在 R 中使用 k-fold CV 手动训练数据?
【发布时间】:2019-11-09 18:19:24
【问题描述】:

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

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,也欢迎使用。

【问题讨论】:

  • 你想做合奏还是什么?最终目标是什么?
  • @NelsonGon 我看到了这个问题,它似乎提供了一种访问索引的方法,但是我想要模型。场景是我需要绘制 PDP,并且我被要求做 k 次,所以在每次折叠之后。因此,我想在第一次折叠后得到训练好的模型,绘制 PDP,然后在第二次折叠后,绘制 PDP,依此类推。
  • mlr 包允许此功能,check it out - 模型参数。
  • @missuse 我试图查看 mlr,但无法理解这是如何完成的,您能否提供最少的代码来说明在 m 场景中的情况?

标签: r machine-learning cross-validation r-caret


【解决方案1】:

这是使用 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)

定义搜索空间(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  

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

另一种选择,我认为更好的方法是在嵌套交叉验证的内部折叠中选择超参数并评估外部折叠,以保持外部折叠模型摆弄。

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

定义内部重采样策略

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

创建一个调整包装器 - 定义内部交叉验证循环中发生的事情

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

【讨论】:

  • 一个小问题,用caret我通常会创建两个数据分区,一个训练集和一个测试集,通常看起来像这样:index &lt;- createDataPartition(dataset$Y, p=0.8, list=FALSE, time=1) dataset_train &lt;- dataset[index,] dataset_test &lt;- dataset[-index,],然后使用dataset_train训练模型,dataset_test 用于实际测试模型的性能。在您的示例中,我看到您使用了整个数据集,我该如何使用mlr 进行划分?
  • 为什么不直接使用caret 方法呢?老实说,它比我在 mlr 中所知道的任何东西都更容易使用。
  • 我只想为每个折叠获取 3 个模型。我在caret 中找不到这样做的方法,而您的漂亮答案似乎为它提供了一种方法。
  • 我的意思是为什么不只使用插入符号中的createDataPartition 而其余的使用mlr 呢?在 mlr 中进行训练/测试拆分的一种方法是:hold &lt;- makeResampleInstance(makeResampleDesc("Holdout", split = 2/3), task = mlr_task),然后是基于 hold$train.inds/hold$test.inds 的子集。顺便检查一下:mlr.mlr-org.com/articles/tutorial/partial_dependence.html,因为你提到你需要 PDP。
  • @terett 由于iml::Predictor$new 喜欢mlr 模型,您可以将rsmpls$models[[1]] 作为模型传递,如果您传递rsmpls$models[[1]]$learner.model,您实际上传递的是kernlab 模型,因此您应该使用@987654357 @ 作为预测函数。简而言之:mdl &lt;- Predictor$new(model = rsmpls$models[[1]], data = X, y = Y) 然后mdl$predict(X) 有效。
【解决方案2】:

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

   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 

【讨论】:

    【解决方案3】:

    卡特中的火车功能简化了模型评估和培训 https://cran.r-project.org/web/packages/caret/vignettes/caret.html

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

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

    【讨论】:

    • “没有理由想要在每个折叠上训练的型号。”,这是广泛的夸大。每个人都有不同的场景,出于研究目的,有这样的场景很有用。
    • 我所说的方式是天真的,我不相信有一种方法可以让在每个折叠中训练的型号 span>
    猜你喜欢
    • 2019-11-09
    • 2021-09-16
    • 2014-05-19
    • 1970-01-01
    • 1970-01-01
    • 2019-01-23
    • 2020-09-14
    • 2019-03-02
    • 2018-06-22
    相关资源
    最近更新 更多