如何用match.fun动态构建含parsnip模型调用的tibble?
动态生成Parsnip模型调用列的问题
现有数据结构
现有如下结构的tibble:
regression_to_parsnip_call_tbl <- tibble::tibble( engine = c( "lm", "brulee", "gee", "glm", "glmer", "glmnet", "gls", "h2o", "keras", "lme", "lmer", "spark", "stan", "stan_glmer" ), mode = "regression" )
需求
需要为该tibble新增一列,存储形如linear_reg(mode = "regression", engine = "lm")的parsnip模型调用,且不希望硬编码目标函数,后续需支持cubist_rules等其他回归模型。
报错信息
尝试相关代码时出现如下报错:
Error in `dplyr::mutate()`: ! Problem while computing `model_spec = purrr::pmap(dplyr::cur_data(), match.fun(mt))`. Caused by error in `get()`: ! object 'mt' of mode 'function' was not found Run `rlang::last_error()` to see where the error occurred.
解决方案
核心思路是通过动态映射模型函数名,结合rlang的符号引用/解引用功能实现无硬编码的模型调用生成,同时用purrr处理逐行逻辑:
方法1:内嵌模型映射规则
先在原表中添加模型函数名的映射,再逐行生成模型对象:
library(dplyr) library(purrr) library(parsnip) library(rlang) regression_to_parsnip_call_tbl <- regression_to_parsnip_call_tbl %>% # 定义引擎与模型函数的映射,后续新增模型只需扩展此处 mutate(model_fn = case_when( engine %in% c("lm", "brulee", "gee", "glm", "glmer", "glmnet", "gls", "h2o", "keras", "lme", "lmer", "spark", "stan", "stan_glmer") ~ "linear_reg", engine == "cubist" ~ "cubist_rules", # 可继续添加更多模型映射 TRUE ~ NA_character_ )) %>% # 动态调用模型函数生成调用对象 mutate(model_spec = pmap(list(mode, engine, model_fn), function(mode_val, engine_val, fn_name) { # 将字符串函数名转为符号,再解引用调用 fn_sym <- sym(fn_name) eval_tidy(expr(!!fn_sym(mode = !!mode_val, engine = !!engine_val))) }))
方法2:独立映射表实现灵活扩展
如果需要更清晰的管理逻辑,可以单独定义模型-引擎映射表,再关联生成:
# 独立定义模型-引擎映射表,后续新增模型/引擎只需修改此表 model_engine_map <- tibble::tibble( engine = c( "lm", "brulee", "gee", "glm", "glmer", "glmnet", "gls", "h2o", "keras", "lme", "lmer", "spark", "stan", "stan_glmer", "cubist" ), model_fn = c( rep("linear_reg", 14), "cubist_rules" ), mode = "regression" ) # 关联原表并生成模型调用 regression_to_parsnip_call_tbl <- regression_to_parsnip_call_tbl %>% left_join(model_engine_map, by = c("engine", "mode")) %>% mutate(model_spec = pmap(list(mode, engine, model_fn), function(mode_val, engine_val, fn_name) { fn_sym <- sym(fn_name) eval_tidy(expr(!!fn_sym(mode = !!mode_val, engine = !!engine_val))) }))
关键说明
- 用
rlang::sym()将字符串形式的函数名转为符号,再通过!!解引用实现动态调用,彻底避免硬编码函数名 - 模型与引擎的映射逻辑单独抽离,后续新增模型(如
cubist_rules)只需扩展映射规则,无需修改核心生成代码 purrr::pmap()负责逐行传递参数,确保每个模型调用的mode和engine参数准确匹配
内容的提问来源于stack exchange,提问作者MCP_infiltrator
相关产品推荐
相关产品推荐

