mlr中makeStackedLearner为何不支持生存模型?能否实现堆叠?
makeStackedLearner不支持生存模型的原因与自定义实现方案 你遇到的这个问题本质是mlr的makeStackedLearner从设计之初就只适配了回归、二分类和多分类任务,完全没考虑生存分析这种特殊任务类型。从你贴的那段源码就能看出来:
td = getTaskDesc(task)
type = ifelse(td$type == "regr", "regr", ifelse(length(td$class.levels) == 2L, "classif", "multiclassif"))
这段代码会把任务类型强行归类到regr/classif/multiclassif三类,而生存任务的类型是surv,不在这个判断逻辑里,结果就被默认当成了分类任务处理——这就是报错的核心原因:生存模型输出的风险值是数值型,但代码误以为要输出分类用的因子类型,自然就触发了类型不匹配的错误。
至于官方为什么没做生存模型的支持,主要是因为生存分析的输出比普通回归/分类复杂得多:除了风险值,还有生存函数、累积风险等特殊指标,堆叠策略(比如简单平均、元模型拟合)需要针对这些特殊输出做定制,而makeStackedLearner的底层逻辑没有做这部分适配,所以直接排除了生存任务。
不过你想要的多个生存模型结果简单平均+重采样循环其实很好实现,不用依赖makeStackedLearner,我们可以手动自定义一个生存学习器来完成这个需求,同时保留并行化能力:
library(survival) library(mlr) library(parallelMap) # 加载数据并预处理生存任务 data(veteran) set.seed(24601) mas.task <- makeSurvTask(id = "MAS", data = veteran, target = c("time", "status")) mas.task <- createDummyFeatures(mas.task) # 定义重采样策略 inner <- makeResampleDesc("CV", iters=2, stratify=TRUE) outer <- makeResampleDesc("CV", iters=2, stratify=TRUE) # 定义基础生存学习器集合 cox.lrn <- makeLearner(cl="surv.coxph", id = "coxph", predict.type="response") glmboost.lrn <- makeLearner(cl="surv.glmboost", id = "glmBoost", predict.type="response", use.formula=TRUE, center=TRUE) rfsrc.lrn <- makeLearner(cl="surv.randomForestSRC", id = "rfsrc", predict.type="response") base_learners <- list(cox.lrn, glmboost.lrn, rfsrc.lrn) # 启动并行化(针对重采样迭代) parallelStart(mode="multicore", cpus=12, level="mlr.resample", show.info = TRUE, logging=TRUE) # 自定义堆叠生存学习器:实现基础模型预测值的简单平均 stacked_lrn <- makeLearner("surv.custom", # 训练阶段:训练所有基础学习器并保存 train = function(task, model, ...) { base_models <- lapply(base_learners, function(lrn) train(lrn, task)) return(list(base_models = base_models)) }, # 预测阶段:收集所有基础模型的风险值,按样本求平均 predict = function(model, newdata, ...) { # 获取每个基础模型的风险预测值 base_preds <- lapply(model$base_models, function(bm) predict(bm, newdata = newdata)$data$response) # 对每个样本的多个风险值做平均 avg_pred <- rowMeans(do.call(cbind, base_preds)) # 返回符合生存预测格式的结果 return(list(response = avg_pred)) } ) # 执行外层重采样验证 stacked_resample <- resample( task = mas.task, learner = stacked_lrn, resampling = outer, measures = list(cindex), show.info = TRUE ) # 查看堆叠模型的性能指标 print(stacked_resample$aggr) # 停止并行化 parallelStop()
代码关键点说明:
- 用
makeLearner("surv.custom")创建自定义生存学习器,手动实现train和predict逻辑,完全避开makeStackedLearner的类型限制 train方法负责训练所有基础生存模型并保存,predict方法收集每个模型的风险值后按样本求平均- 直接用
resample函数将自定义学习器融入外层交叉验证,并行化依然生效(因为指定了level="mlr.resample",mlr会自动分配重采样迭代到多核)
如果之后你想尝试更复杂的堆叠策略(比如用元模型学习基础模型的权重),也可以用类似的思路:在train阶段先通过内层重采样得到基础模型的预测值,再用这些预测值作为特征训练一个生存元模型(比如cox模型),预测阶段先用基础模型得到预测值,再输入元模型得到最终结果。
内容的提问来源于stack exchange,提问作者panda

