如何为tidymodels生态下的集成模型设置自定义权重?
自定义权重集成模型构建(基于tidymodels与stacks)
需求概述
我需要构建带自定义权重的集成模型:用tidymodels训练多个子模型后,手动指定各子模型的权重(比如等权重0.5/0.5)。stacks包在自动优化权重上表现出色,但我需要手动控制权重;同时希望最终的集成模型能像stacks输出的对象一样,兼容DALEXtra进行模型解释。
现有实现(stacks自动加权)
以下是用stacks自动生成权重的代码,当前输出的权重不符合自定义需求:
## 加载依赖包 library(tidymodels) library(stacks) library(DALEXtra) # 抽取ames数据集样本 set.seed(1) df <- ames %>% sample_n(500) # 数据划分与重采样设置 set.seed(1) df_splits <- initial_split(df) df_train <- training(df_splits) df_test <- testing(df_splits) set.seed(1) df_folds <- vfold_cv(df_train, v = 4) # 定义两个特征配方 rec_small <- recipe(Sale_Price ~ Gr_Liv_Area, data = df) rec_big <- recipe(Sale_Price ~ BsmtFin_SF_1 + First_Flr_SF + Second_Flr_SF, data = df) # 随机森林模型规格 rand_forest_ranger_spec <- rand_forest() %>% set_engine('ranger') %>% set_mode('regression') # 构建工作流集合 wf_rfs <- workflow_set( preproc = list(rec_small, rec_big), models = list(rf = rand_forest_ranger_spec) ) # 训练子模型 grid_ctrl <- control_grid( save_pred = TRUE, parallel_over = "everything", save_workflow = TRUE ) grid_results <- wf_rfs %>% workflow_map( seed = 1503, resamples = df_folds, control = grid_ctrl ) # stacks自动加权集成 df_st <- stacks() %>% add_candidates(grid_results) set.seed(1) df_model_st <- df_st %>% blend_predictions() # 查看自动生成的权重公式 df_model_st$equations$numeric # 当前输出:-42148.1667470673 + (recipe_1_rf_1_1 * 0.13109783287876) + (recipe_2_rf_1_1 * 1.08833216052151) # 期望输出:0 + (recipe_1_rf_1_1 * .5) + (recipe_2_rf_1_1 * .5)
模型解释流程(基于stacks模型)
以下是用DALEXtra对stacks集成模型做解释的代码,这是我希望保留的功能:
# 拟合集成模型成员 df_model_st_fitted <- df_model_st %>% fit_members() # 准备解释用特征与数据 vip_features <- c("Gr_Liv_Area", "BsmtFin_SF_1", "First_Flr_SF", "Second_Flr_SF") vip_train <- df %>% select(all_of(vip_features)) # 创建模型解释器 explainer_blended_rf <- explain_tidymodels( df_model_st_fitted, data = vip_train, y = df$Sale_Price, label = "Blended Random Forest", verbose = FALSE ) # 生成变量重要性图(VIP) vip_example <- explain_tidymodels( df_model_st_fitted, data = vip_train, y = df$Sale_Price, label = "Blended RF", verbose = FALSE ) %>% model_parts() plot(vip_example) # 生成累积局部效应图(AL Plots) al_rf <- model_profile( explainer = explainer_blended_rf, type = "accumulated", variables = names(vip_train) ) plot(al_rf) + ggtitle("Accumulated-local profiles")
解决方法
方法1:修改stacks模型的权重
直接修改stacks生成的模型对象中的系数,替换为自定义权重后再拟合成员模型:
# 定义自定义权重(截距为0,两个子模型各0.5) custom_weights <- c(0, 0.5, 0.5) names(custom_weights) <- names(df_model_st$coefficients$numeric) # 更新模型系数 df_model_st$coefficients$numeric <- custom_weights # 重新拟合成员模型 df_custom_st_fitted <- df_model_st %>% fit_members() # 验证自定义权重的预测效果 predict(df_custom_st_fitted, df_test)
方法2:手动构建兼容tidymodels的自定义集成模型
如果不想依赖stacks,可以手动构建符合tidymodels规范的集成模型,确保能被DALEXtra识别:
# 1. 预先训练并保存每个子模型的完整拟合对象 wf_small <- wf_rfs$workflow[[1]] %>% fit(df_train) wf_big <- wf_rfs$workflow[[2]] %>% fit(df_train) # 2. 定义自定义集成模型的预测函数 custom_ensemble_predict <- function(new_data) { pred_small <- predict(wf_small, new_data)$.pred pred_big <- predict(wf_big, new_data)$.pred # 等权重加权计算最终预测值 tibble(.pred = 0.5 * pred_small + 0.5 * pred_big) } # 3. 包装成parsnip兼容的自定义模型 custom_ensemble_spec <- parsnip::model_spec( mode = "regression", engine = "custom" ) %>% parsnip::set_engine( engine = "custom", model = list(wf_small = wf_small, wf_big = wf_big) ) # 注册自定义模型的拟合与预测方法 parsnip::set_model_engine("custom", "regression", "fit") <- function(object, formula, data, ...) { object$fit <- list(wf_small = wf_small, wf_big = wf_big) object } parsnip::set_model_engine("custom", "regression", "predict") <- function(object, new_data, ...) { custom_ensemble_predict(new_data) } # 拟合自定义集成模型 custom_ensemble_fit <- custom_ensemble_spec %>% fit(Sale_Price ~ ., data = df_train) # 用DALEXtra进行模型解释 explainer_custom <- explain_tidymodels( custom_ensemble_fit, data = vip_train, y = df$Sale_Price, label = "Custom Weighted Ensemble", verbose = FALSE ) # 生成变量重要性图 vip_custom <- model_parts(explainer_custom) plot(vip_custom)
内容的提问来源于stack exchange,提问作者Econ_Modeler
相关产品推荐
相关产品推荐

