执行initial_split()后,如何将目标变量从chr转为fct类型
解决tidymodels中last_fit因目标变量非因子报错的问题
问题
运行last_fit()时触发报错,提示分类模型的目标变量必须是因子类型。常规数据框可以直接转换变量类型,但不清楚如何处理initial_split()生成的split对象。
错误信息
x train/test split: preprocessor 1/1, model 1/1: Error in `check_outcome()`: ! For a classification model, the outcome should be a factor. Warning message: All models failed. Run `show_notes(.Last.tune.result)` for more information. Error in `check_outcome()`: ! For a classification model, the outcome should be a factor.
复现代码
library(tidyverse) library(tidymodels) # 建模数据 df <- read_csv("https://gist.githubusercontent.com/netj/8836201/raw/6f9306ad21398ea43cba4f7d537619d0e07d5ae3/iris.csv") %>% mutate( virg = case_when( variety == "Virginica" ~ 'yes', TRUE ~ 'No', )) %>% select(-variety) # 拆分数据 df_split <- initial_split(df, prop = .75, strata = virg) # 示例:单独转换训练/测试集的变量类型 df_training <- df_split %>% training() %>% mutate(virg = as.factor(virg)) df_test <- df_split %>% testing() %>% mutate(virg = as.factor(virg)) # 随机森林模型 rf_model <- rand_forest() %>% set_engine('randomForest') %>% set_mode('classification') # 触发报错的last_fit调用 df_last_fit <- rf_model %>% last_fit(virg ~ sepal.length + sepal.width + petal.length + petal.width, split = df_split )
解决方案
方法1:拆分前转换目标变量(推荐)
在数据拆分前就把目标变量转为因子,这样split对象中的训练和测试集会自动继承因子类型,无需后续手动处理:
df <- read_csv("https://gist.githubusercontent.com/netj/8836201/raw/6f9306ad21398ea43cba4f7d537619d0e07d5ae3/iris.csv") %>% mutate( virg = case_when( variety == "Virginica" ~ 'yes', TRUE ~ 'No', ) %>% as.factor() # 直接转换为因子 ) %>% select(-variety) # 正常拆分数据 df_split <- initial_split(df, prop = .75, strata = virg) # 直接运行last_fit df_last_fit <- rf_model %>% last_fit(virg ~ sepal.length + sepal.width + petal.length + petal.width, split = df_split )
方法2:修改已拆分的rsplit对象
如果已经完成数据拆分,可提取训练/测试集转换类型后,重新构建split对象:
# 提取并转换训练、测试集的目标变量 train_data <- training(df_split) %>% mutate(virg = as.factor(virg)) test_data <- testing(df_split) %>% mutate(virg = as.factor(virg)) # 重新构建rsplit对象 df_split_fixed <- make_splits(list(train = train_data, test = test_data), data = bind_rows(train_data, test_data)) # 使用修复后的split对象运行last_fit df_last_fit <- rf_model %>% last_fit(virg ~ sepal.length + sepal.width + petal.length + petal.width, split = df_split_fixed )
方法3:使用配方(Recipe)预处理(更符合tidymodels流程)
将变量类型转换作为预处理步骤整合到工作流中,这是tidymodels推荐的标准化流程:
# 创建配方,将字符型目标变量转为因子 iris_recipe <- recipe(virg ~ ., data = df) %>% step_string2factor(virg) # 构建模型工作流 rf_workflow <- workflow() %>% add_recipe(iris_recipe) %>% add_model(rf_model) # 运行last_fit df_last_fit <- rf_workflow %>% last_fit(split = df_split)
内容的提问来源于stack exchange,提问作者user16329246
相关产品推荐
相关产品推荐

