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

使用mlr3构建MaxEnt模型学习器的错误排查与调参疑问

问题解答:mlr3构建maxnet学习器的错误与调参问题

1) 解决"only defined on a data frame with all numeric-alike variables"错误

这个错误的核心原因是maxnet要求输入的特征数据和响应变量必须是数值类型,你的代码里存在两处不符合要求的问题:

响应变量类型错误

maxnet的p参数需要接收0/1的数值向量,但你将presence转成了因子,task$data(cols = task$target_names)返回的是因子列,不是数值格式。

特征数据包含非数值类型

你的学习器声明支持factor和ordered类型特征,但maxnet无法直接处理这类非数值数据,必须转换为数值格式。

修复方案:

修改LearnerClassifMaxnet的.train和.predict函数,添加类型转换逻辑:

  • 在.train中,将响应变量转成0/1数值,将特征数据中的因子/有序因子转成数值(或哑编码,示例采用简单数值转换,可根据需求调整)
  • 在.predict中,对预测数据做同样的类型转换

2) 调参代码能否正确更新?

你初始化时设置的param_set$values = list(...)是默认参数值,在调参过程中可以正确更新。

只要通过以下方式修改参数,.train和.predict函数中通过self$param_set$get_values(tags = "train")/tags = "predict"就能获取到最新的参数值:

  • 手动修改:learner_test$param_set$set_values(regmult = 2, response_type = "logistic")
  • 用mlr3tuning自动调参:tuner会自动更新param_set的values

注意点:

参数的tags设置正确(train标签的参数在训练阶段生效,predict标签的在预测阶段生效),你的代码中已经正确设置了tags,所以调参时参数会被正确传递到对应的阶段。


修改后的完整Learner代码

LearnerClassifMaxnet = R6Class("LearnerClassifMaxnet",
                               inherit = LearnerClassif,
                               public = list(
                                 initialize = function() {
                                   
                                   ## 定义学习器的参数集
                                   param_set = ps(
                                     regmult                = p_dbl(default = 1, tags = "train"),
                                     addsamplestobackground = p_lgl(default = TRUE, tags = "train"),
                                     clamp                  = p_lgl(default = TRUE, tags = "predict"),
                                     classes                = p_fct(default = "default", levels = c("default", "l", "lq", "h", "lqh", "lqhp", "lqhpt"), tags = "train"),
                                     response_type          = p_fct(default = "cloglog", levels = c("link","exponential","cloglog","logistic"), tags = "predict")
                                   )
                                   
                                   param_set$values = list(regmult = 1, addsamplestobackground = TRUE, clamp = TRUE, classes = "default", response_type = "cloglog")
                                   
                                   ## 初始化学习器
                                   super$initialize(
                                     id = "classif.maxnet",
                                     feature_types = c("logical", "integer", "numeric", "factor", "ordered"),
                                     predict_types = "prob",
                                     packages = c("maxnet", "dplyr"), # 添加dplyr用于类型转换
                                     param_set = param_set,
                                     properties = c("weights", "twoclass"),
                                     label = "Maximum Entropy",
                                     man = "mlr3learners::mlr_learners_classif.maxnet"
                                   )
                                 }
                               ),
                               
                               ## 定义训练函数
                               private = list(
                                 .train = function(task) {
                                   pv = self$param_set$get_values(tags = "train")
                                   if ("weights" %in% task$properties) {
                                     pv$weights = task$weights$weight 
                                   }

                                   # 转换响应变量为0/1数值
                                   p = as.integer(task$data(cols = task$target_names)[[1]]) - 1
                                   # 转换特征数据:因子/有序因子转数值,转成矩阵
                                   data = task$data(cols = task$feature_names) %>%
                                     mutate(across(c(factor, ordered), as.numeric)) %>%
                                     as.matrix()

                                   ## 构建maxnet模型
                                   invoke(
                                     maxnet::maxnet,
                                     p = p,
                                     data = data,
                                     f = maxnet.formula(p = p, data = data, classes = pv$classes),
                                     regmult = pv$regmult,
                                     regfun = maxnet.default.regularization,
                                     addsamplestobackground = pv$addsamplestobackground
                                   )
                                 },
                                 
                                 ## 定义预测函数
                                 .predict = function(task){
                                   pv = self$param_set$get_values(tags = "predict")
                                   
                                   ## 确保训练和预测数据列顺序一致
                                   newdata = mlr3extralearners:::ordered_features(task, self)
                                   
                                   # 转换预测数据类型,和训练数据保持一致
                                   newdata = newdata %>%
                                     mutate(across(c(factor, ordered), as.numeric)) %>%
                                     as.matrix()
                                   
                                   ## 计算预测值
                                   prob = invoke(predict, object = self$model, newdata = newdata, clamp = pv$clamp, type = pv$response_type)
                                   
                                   # 整理成mlr3要求的概率格式(两列:0和1的概率)
                                   prob_matrix = cbind(1 - prob, prob)
                                   colnames(prob_matrix) = task$class_names
                                   
                                   list(prob = prob_matrix)
                                 }
                               )
)

修改后的错误复现代码

library(mlr3)
library(mlr3learners)
library(paradox)
library(R6)
library(mlr3misc)
library(maxnet)
library(dplyr) # 加载dplyr用于类型转换

source("C:/R_functions/LearnerClassifMaxnet.R")
data("bradypus")
bradypus_data <- bradypus[, !(colnames(bradypus) %in% c("ecoreg"))]
bradypus_data$presence <- as.factor(bradypus_data$presence)
bradypus_task <- mlr3::as_task_classif(x = bradypus_data, target = "presence", positive = "1")

learner_test = LearnerClassifMaxnet$new()
learner_test$train(bradypus_task)
p = learner_test$predict(bradypus_task)

# 查看预测结果
print(p$prob)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 10:55:54