You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

mlr3基准测试:如何比较含不同分组预测变量的XGBoost模型?

用mlr3基准测试比较不同变量组模型的问题解决

问题描述

我的数据预测变量分两组(问卷得分、生物变量),想通过mlr3基准测试对比不同组训练的XGBoost模型,但运行代码后Friedman事后检验报错:

警告:仅可用两个学习器,返回全局检验。
错误:不是无重复的完全区组设计

原代码如下:

reg.tasks=list()
reg.tasks$everything = as_task_classif(df,target='Reiteration',id='everything')
reg.tasks$biological = as_task_classif(df %>% dplyr::select(any_of(biological.vars)),target='Reiteration',id='everything')

future::plan(list('multisession'))
at=auto_tuner(method=tnr('random_search'),
              learner=lts(lrn('classif.xgboost')),
              resampling=rsmp('cv',folds=4),
              measures=msr('classif.bacc'),
              term_time=1*60))) # just to test
outer_resampling=rsmp('cv',folds=3)

bm_design=data.table::data.table(
  task=c(reg.tasks$everything,reg.tasks$everything,reg.tasks$biological), 
  learner=list(at,lrn('classif.featureless'),at),
  resampling=list(outer_reampling,outer_resampling,outer_resampling)
bmr=bechnmark(bm_design,store_models=TRUE)

bma=as.BenchmarkAggr(brr,measures=msr('classif.bacc'))
bma$friedman_posthoc()

问题出在哪

  1. 模型区分逻辑错误:你想对比「全变量XGBoost、生物变量XGBoost、无特征模型」,但现在把变量组做成不同task,同时重复使用同一个auto_tuner学习器,导致mlr3只识别出2种独立学习器(调优XGBoost、无特征),触发“仅两个学习器”的警告。
  2. 区组设计不完整:Friedman检验要求每个外层CV折(区组)里,所有待对比的模型都要有结果。现在everything任务配了2个学习器,biological任务只配了1个,导致部分折缺少模型结果,不符合无重复完全区组设计要求,直接报错。
  3. 代码笔误:outer_reampling(应为outer_resampling)、bechnmark(应为benchmark)、brr(应为bmr)这些拼写错误会直接导致运行失败。

怎么改

方案一:保留多task,构建完整基准设计

如果坚持用不同task区分变量组,要给每个task都搭配所有待比较的学习器,确保每个区组的结果完整:

library(mlr3)
library(mlr3tuning)
library(data.table)
library(dplyr)

# 构建不同变量组的任务,注意每个task的id要唯一
reg.tasks = list(
  everything = as_task_classif(df, target = 'Reiteration', id = 'all_vars'),
  biological = as_task_classif(df %>% select(any_of(biological.vars), Reiteration), target = 'Reiteration', id = 'bio_vars')
)

# 定义基础学习器和调优器
xgboost_lrn = lrn('classif.xgboost')
at = auto_tuner(
  method = tnr('random_search'),
  learner = xgboost_lrn,
  resampling = rsmp('cv', folds = 4),
  measures = msr('classif.bacc'),
  term_time = 1*60
)
featureless_lrn = lrn('classif.featureless')

# 构建完整设计:每个任务都配所有学习器
bm_design = data.table::data.table(
  task = c(reg.tasks$everything, reg.tasks$everything, reg.tasks$biological, reg.tasks$biological),
  learner = list(at, featureless_lrn, at, featureless_lrn),
  resampling = list(rsmp('cv', folds=3), rsmp('cv', folds=3), rsmp('cv', folds=3), rsmp('cv', folds=3))
)

# 运行基准测试
future::plan('multisession')
bmr = benchmark(bm_design, store_models = TRUE)

# 聚合结果并检验
bma = as.BenchmarkAggr(bmr, measures = msr('classif.bacc'))
bma$friedman() # 先跑全局检验
# 若要事后检验,建议再加一个问卷变量组的task,凑够3种以上模型

方案二:用预处理包装器统一处理变量选择(更推荐)

把变量分组转化为学习器的预处理步骤,所有模型在同一个task上运行,更符合mlr3的设计逻辑:

library(mlr3)
library(mlr3tuning)
library(mlr3pipelines)
library(data.table)
library(dplyr)

# 定义变量筛选的预处理组件
filter_all = po('select', selector = selector_all())
filter_bio = po('select', selector = selector_name(biological.vars))
filter_quest = po('select', selector = selector_name(questionnaire.vars)) # 假设你有问卷变量列表

# 构建带变量筛选的XGBoost学习器,给每个学习器唯一id
xgboost_all = filter_all %>>% lrn('classif.xgboost')
xgboost_all$id = 'xgboost_all_vars'

xgboost_bio = filter_bio %>>% lrn('classif.xgboost')
xgboost_bio$id = 'xgboost_bio_vars'

xgboost_quest = filter_quest %>>% lrn('classif.xgboost')
xgboost_quest$id = 'xgboost_quest_vars'

# 给每个带筛选的学习器加调优
at_all = auto_tuner(
  method = tnr('random_search'),
  learner = xgboost_all,
  resampling = rsmp('cv', folds = 4),
  measures = msr('classif.bacc'),
  term_time = 1*60
)

at_bio = auto_tuner(
  method = tnr('random_search'),
  learner = xgboost_bio,
  resampling = rsmp('cv', folds = 4),
  measures = msr('classif.bacc'),
  term_time = 1*60
)

at_quest = auto_tuner(
  method = tnr('random_search'),
  learner = xgboost_quest,
  resampling = rsmp('cv', folds = 4),
  measures = msr('classif.bacc'),
  term_time = 1*60
)

# 构建基准设计:同一个task,多个不同的学习器
task = as_task_classif(df, target = 'Reiteration', id = 'full_data')
featureless_lrn = lrn('classif.featureless')

bm_design = data.table::data.table(
  task = list(task, task, task, task),
  learner = list(at_all, at_bio, at_quest, featureless_lrn),
  resampling = list(rsmp('cv', folds=3), rsmp('cv', folds=3), rsmp('cv', folds=3), rsmp('cv', folds=3))
)

# 运行基准测试
future::plan('multisession')
bmr = benchmark(bm_design, store_models = TRUE)

# 聚合结果并做检验
bma = as.BenchmarkAggr(bmr, measures = msr('classif.bacc'))
bma$friedman() # 全局检验
bma$friedman_posthoc() # 现在有4个模型,满足事后检验要求

关键提醒

  • Friedman事后检验需要至少3个待对比的模型,所以设计里要保证有3种及以上独立的模型/学习器组合。
  • 基准设计必须是完全区组设计:每个外层CV折里,所有待对比的模型都要运行一次,不能缺结果。
  • 每个学习器的id必须唯一,否则聚合结果时会被合并,导致无法区分不同模型。

内容的提问来源于stack exchange,提问作者JacquieS

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 17:27:17