mlr3中实现CV覆盖全流程仅对分类器做网格搜索调参
解决方案
要实现10折CV覆盖整个流水线,且每个fold中先完成预处理(ANOVA过滤+PCA)再对逻辑回归(LR)调参,核心是让预处理在每个CV fold中仅执行一次,避免重复计算;同时将LR的调参限制在预处理后的训练数据上。以下是具体实现步骤:
1. 加载依赖包
library(mlr3) library(mlr3pipelines) library(mlr3tuning)
2. 定义固定参数的预处理流水线
将ANOVA过滤和PCA封装为固定参数的预处理管道,后续每个fold仅拟合一次:
# 预处理管道:固定参数,不参与调参 preproc_pipe <- po("filter", filter = flt("anova"), filter.frac = .5) %>>% po("pca", rank.=10)
3. 定义LR学习器与调参参数集
直接针对LR学习器定义参数集,无需添加前缀(因为我们单独对LR调参):
# LR学习器 lr_learner <- lrn('classif.log_reg', predict_type = "prob") # LR的调参参数集 paramset <- ParamSet$new(list( ParamDbl$new("epsilon", lower = 0, upper = 1e-6 ), ParamDbl$new("maxit", lower = 5, upper = 40, tag = 'budget' ) ))
4. 执行带内层调参的10折CV
遍历每个外层CV fold,先完成预处理,再在预处理后的训练数据上对LR做网格搜索调参,最后用最优参数评估测试集:
# 替换为你的任务,比如 task = tsk("iris") task <- YOUR_TASK_HERE # 外层10折CV resampling_outer <- rsmp("cv", folds = 10) resampling_outer$instantiate(task) # 网格搜索调参器(可调整resolution控制网格密度) tuner <- tnr("grid_search", resolution = 10) terminator <- trm("none") # 网格搜索无需终止器 # 存储结果 results <- data.table() # 遍历每个外层fold for (i in seq_len(resampling_outer$iters)) { # 拆分当前fold的训练/测试集 train_idx <- resampling_outer$train_set(i) test_idx <- resampling_outer$test_set(i) task_train <- task$clone()$filter(train_idx) task_test <- task$clone()$filter(test_idx) # 拟合预处理管道,转换训练/测试数据 preproc_learner <- GraphLearner$new(preproc_pipe) preproc_learner$train(task_train) task_train_preproc <- preproc_learner$predict(task_train) task_test_preproc <- preproc_learner$predict(task_test) # 内层调参实例:在预处理后的训练集上搜索LR最优参数 instance_inner <- TuningInstanceSingleCrit$new( task = task_train_preproc, learner = lr_learner, resampling = rsmp("holdout"), # 内层用holdout加速,也可换为3折CV measure = msr("classif.ce"), search_space = paramset, terminator = terminator ) # 执行网格搜索 tuner$optimize(instance_inner) # 用最优参数训练LR,评估测试集 lr_opt <- lr_learner$clone()$set_param_values(instance_inner$result_learner_param_vals) lr_opt$train(task_train_preproc) pred <- lr_opt$predict(task_test_preproc) # 记录当前fold的结果 results <- rbind(results, data.table( fold = i, test_accuracy = pred$score(msr("classif.acc")), best_epsilon = instance_inner$result_learner_param_vals$epsilon, best_maxit = instance_inner$result_learner_param_vals$maxit )) } # 查看10折CV的平均性能 cat("10折CV平均准确率:", mean(results$test_accuracy), "\n")
关键说明
- 预处理仅执行一次 per fold:每个外层fold中,预处理管道仅在训练集上拟合一次,然后同时转换训练和测试数据,避免了每个调参组合重复执行过滤和PCA,大幅减少耗时。
- 调参仅针对LR:网格搜索仅在预处理后的训练数据上对LR参数进行,不涉及预处理步骤的参数。
- 灵活调整内层验证策略:内层可选择
holdout(快速)或多折CV(更稳定),根据需求平衡速度与性能可靠性。
内容的提问来源于stack exchange,提问作者Haleh
相关产品推荐
相关产品推荐

