使用tidymodels和ranger构建随机森林分类模型的因子报错问题
问题分析与修正
核心错误原因
- 结果变量编码错误:你用
recode_factor(y1,1= "yes",2= "no")时,忽略了y1是rbinom生成的0/1取值,没有2这个值,导致所有0被转为NA,最终结果变量只有yes一个有效类别,缺失了no类别。 cbind导致的数据类型丢失:cbind会将所有向量转为同一类型(这里因子y1被转为字符),再用as.data.frame转换时,虽然会变回因子,但此时结果变量的类别已经不完整,且可能引入隐性问题。
排查步骤
- 查看
dat_set %>% count(y1)的输出,会发现只有yes和大量NA,没有no类别,这直接说明结果变量编码完全错误。 - 用
str(dat_set)查看数据集结构,确认y1的类型和类别是否符合预期。
修正后的代码
library(tidyverse) library(tidymodels) library(themis) library(vip) library(forcats) set.seed(987) n = 1500 # 模拟数据:修正结果变量编码,改用data.frame直接构建避免cbind问题 v1 = sample(c(0,1), size = n, replace = TRUE) v2 = round(runif(n, 18, 80)) v3 = sample(c(0,1), size = n, replace = TRUE) v4 = sample(c(0,1), size = n, replace = TRUE) v5 = sample(c(0,1), size = n, replace = TRUE) v6 = rbinom(n = n, size = 1, prob = .50) xb = -9 + 3.5*v1 + 0.2*v2 + 0*v3 + 0*v4 +0*v5 + 0*v6 p = 1/(1 + exp(-xb)) y1 = rbinom(n = n, size = 1, prob = p) # 修正:映射0到no,1到yes,确保所有取值都被覆盖 y1 = dplyr::recode_factor(y1, `0` = "no", `1` = "yes") # 直接用data.frame构建,避免cbind导致的类型转换问题 dat_set = data.frame(v1, v2, v3, v4, v5, v6, y1) # 查看结果变量分布,确认两个类别都存在 dat_set %>% count(y1) class(dat_set$y1) # 拆分训练集和测试集 set.seed(123) rf_split = initial_split(dat_set, strata = y1) rf_train = training(rf_split) rf_test = testing(rf_split) # 构建交叉验证折数 set.seed(234) rf_folds = vfold_cv(rf_train, strata = y1) # 配方、模型和工作流 ranger_recipe = recipe(formula = y1 ~ ., data = rf_train) ranger_spec = rand_forest(mtry = tune(), min_n = tune(), trees = 1000) %>% set_mode("classification") %>% set_engine("ranger", importance = "impurity") ranger_workflow = workflow() %>% add_recipe(ranger_recipe) %>% add_model(ranger_spec) # 调参 set.seed(93186) ranger_tune = tune_grid(ranger_workflow, resamples = rf_folds, control = control_resamples(save_pred = TRUE))
额外建议
- 避免用
cbind混合不同类型的向量构建数据框,直接用data.frame()或tibble()更安全,能保留原始数据类型。 - 每次生成结果变量后,务必用
count()查看类别分布,确认没有缺失或错误编码的情况。 - 对于分类模型,结果变量必须至少包含两个不同的类别,否则会触发类似的报错。
内容的提问来源于stack exchange,提问作者George
相关产品推荐
相关产品推荐

