基于XGBoost的堆叠集成学习函数报错排查求助
堆叠集成模型错误排查与修正
错误根源分析
出现assert_factor(truth, min.len = 1L, n.levels = 2L, any.missing = FALSE) : argument "truth" is missing, with no default错误,核心原因有三点:
- 目标列名称不匹配:训练集样例的目标列是
target,但代码中创建任务时指定的目标是CR,导致任务无法识别真实标签,后续训练流程缺失truth参数。 - 自定义度量命名冲突:自定义AUC度量的函数名和
pROC包的auc函数重名,导致内部调用时逻辑混乱。 - 元学习器参数冗余:
makeStackedLearner的metalearner.control重复设置ntree,和之前给meta_lrn设置的参数冲突。
代码修正步骤
- 修正目标列名称:将创建任务时的
target参数改为训练集实际的目标列名"target" - 重命名自定义AUC度量:把自定义度量的id和函数名改为
custom_auc,避免和pROC::auc冲突 - 移除冗余参数设置:删除
stack_learner$par.vals中重复的ntree设置 - 统一测试集目标列处理:确保测试集的目标列名称与训练集一致
完整修正代码
super_train <- function(data_list, n_models = 10, cpus = 32) { # Prepare data train <- data_list[[1]] test <- data_list[[2]] train[,1] <- factor(train[,1]) test[,1] <- factor(test[,1]) # 修正目标列名称为实际的"target" task <- makeClassifTask(data = train, target = "target") print(task$type) # Create base learners base_learners <- list() for (i in 1:n_models) { ctrl <- makeTuneControlMBO() lrn <- makeLearner("classif.xgboost", predict.type = "prob") ps <- makeParamSet( makeDiscreteParam("booster", values = c("gbtree", "gblinear")), makeNumericParam("eta", lower = 0.01, upper = 0.08), makeIntegerParam("max_depth", lower = 2L, upper = 11L), makeNumericParam("alpha", lower = 0L, upper = 8), makeNumericParam("lambda", lower = 0L, upper = 8), makeNumericParam("gamma", lower = 0L, upper = 8), makeNumericParam("min_child_weight", lower = 2L, upper = 8L), makeNumericParam("subsample", lower = 0.5, upper = 1), makeNumericParam("colsample_bytree", lower = 0.5, upper = 1), makeNumericParam("scale_pos_weight", lower = 1, upper = 10) ) # 重命名自定义AUC度量,避免和pROC::auc冲突 custom_auc <- makeMeasure(id = "custom_classif.auc", name = "Area under ROC curve", minimize = FALSE, fun = function(truth, pred, lev = NULL, model = NULL) { require(pROC) response <- factor(truth, levels = lev) prediction <- pred[, lev[2]] roc_obj <- roc(response, prediction) auc_obj <- pROC::auc(roc_obj) # 明确指定pROC::auc避免混淆 return(auc_obj) }) resampling_desc <- makeResampleDesc("CV", iters = 10) res <- tuneParams(lrn, task, resampling = resampling_desc, measures = list(custom_auc), par.set = ps, control = ctrl) base_learners[[i]] <- res$learner } # Create meta-learner meta_lrn <- makeLearner("classif.randomForest", predict.type = "prob") meta_lrn$par.vals <- list(ntree = 100, mtry = sqrt(ncol(train)-1), importance = TRUE) # 减去目标列,避免mtry计算错误 # Create stacked ensemble - 移除冗余的metalearner.control设置 stack_learner <- makeStackedLearner(base_learners, metalearner = meta_lrn) # Train stacked ensemble stack_model <- train(stack_learner, task) # Evaluate on test set test_pred <- predict(stack_model, newdata = test)$data return(list(stack_model = stack_model, test_pred = test_pred)) }
测试调用示例
使用提供的训练集样例进行测试:
# 构造数据列表(假设测试集和训练集结构一致) train_data <- structure(list(target = structure(c(1L, 2L, 1L, 2L, 1L, 1L, 2L, 2L, 1L, 1L, 1L, 2L, 1L, 1L, 1L, 1L, 2L, 1L, 1L, 2L), levels = c("0", "1"), class = "factor"), Bone = c(0.68, 0.82, 0.6, 0.63, 0.5, 0.72, 0.66, 0.58, 0.6, 0.6, 0.56, 0.7, 0.59, 0.55, 0.47, 0.6, 0.64, 0.67, 0.62, 0.59), Blood = c(0.54, 0.65, 0.48, 0.54, 0.22, 0.58, 0.51, 0.38, 0.46, 0.42, 0.3, 0.62, 0.4, 0.29, 0.2, 0.48, 0.54, 0.55, 0.37, 0.46), Skin = c(0.77, 0.83, 0.74, 0.75, 0.75, 0.78, 0.75, 0.76, 0.76, 0.76, 0.75, 0.76, 0.76, 0.75, 0.74, 0.75, 0.76, 0.75, 0.75, 0.74), Brain = c(0.51, 0.59, 0.46, 0.5, 0.33, 0.56, 0.49, 0.39, 0.45, 0.46, 0.37, 0.57, 0.43, 0.37, 0.32, 0.47, 0.48, 0.55, 0.43, 0.47), Liver = c(0.58, 0.62, 0.55, 0.58, 0.48, 0.58, 0.62, 0.5, 0.51, 0.55, 0.53, 0.65, 0.54, 0.48, 0.46, 0.57, 0.57, 0.65, 0.59, 0.59), Stomach = c(0.58, 0.65, 0.54, 0.59, 0.5, 0.61, 0.6, 0.51, 0.51, 0.55, 0.56, 0.61, 0.55, 0.51, 0.47, 0.59, 0.55, 0.63, 0.57, 0.59), Heart = c(0.62, 0.66, 0.55, 0.61, 0.44, 0.63, 0.58, 0.51, 0.55, 0.55, 0.46, 0.66, 0.53, 0.47, 0.41, 0.56, 0.57, 0.64, 0.51, 0.56), T.cells = c(0.53, 0.75, 0.5, 0.51, 0.47, 0.66, 0.52, 0.52, 0.53, 0.54, 0.47, 0.56, 0.49, 0.48, 0.45, 0.51, 0.52, 0.55, 0.52, 0.53), B.cells = c(0.52, 0.81, 0.46, 0.47, 0.39, 0.7, 0.49, 0.47, 0.5, 0.54, 0.41, 0.54, 0.44, 0.43, 0.37, 0.48, 0.49, 0.53, 0.48, 0.52)), row.names = c("Pt1", "Pta101", "Pta106", "Ptc11", "Ptc17", "Ptc18", "Ptb2", "Ptm26", "Ptm28", "Pta29", "Pta3", "Pta34", "Ptb37", "Ptb38", "Ptb39", "Ptb4", "Ptc44", "Ptc46", "Ptb47", "Pta48"), class = "data.frame") # 这里用训练集作为测试集示例,实际应替换为真实测试数据 data_list <- list(train_data, train_data) # 调用函数(n_models设为2加快测试) result <- super_train(data_list, n_models = 2)
额外优化说明
- 元学习器的
mtry参数计算时减去了目标列,避免包含标签列导致参数错误 - 自定义AUC度量中明确指定
pROC::auc,彻底消除命名冲突 - 返回值增加了测试集预测结果,方便后续评估
内容的提问来源于stack exchange,提问作者Programming Noob
相关产品推荐
相关产品推荐

