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

为何recipes::bake()会将字符型ID转为值全为NA的因子?

问题:recipes包bake()处理后ID列变为带训练集水平的因子且值全为NA

我有一个字符型ID,希望保留在数据中但不用于训练。查看经过bake()处理后的数据时,发现该ID列变为了包含所有取值水平的因子,但所有值均为NA。

复现代码

# 创建带唯一字符型ID的数据集
myData <- mtcars %>% 
  mutate(myID = paste("j", row_number()))

# 拆分数据集
myDataSplit <- initial_split(myData)

# 查看测试集myID的类型:字符型
class(testing(myDataSplit)$myID) # [1] "character"

# 将myID的角色从'predictor'改为'ID'
myRecipe <- recipe(mpg ~., data = training(myDataSplit)) %>%
  update_role(myID, new_role="ID") 

# 预处理并应用到测试集
myTesting <- myRecipe  %>%
  prep() %>% 
  bake(testing(myDataSplit)) 

问题现象

此时myTesting中的myID变为因子且所有值均为NA:

> unique(myTesting$myID)
[1] <NA>
Levels: j1 j10 j13 j15 j16 j17 j19 j21 j22 j23 j24 j25 j26 j27 j28 j29 j3 j30 j32 j4 j5 j6 j7 j8

已尝试的无效方法

  • 使用step_factor2string(myID)
  • 创建recipe时设置convert_strings = FALSE:
myRecipe <- recipe(mpg ~., data = training(myDataSplit),  convert_strings = FALSE)

我正在使用workflow(),调用predict(myworflow, testing(myDataSplit))时它会自动执行bake操作,这似乎能正常工作,但bake()单独处理时的问题让我觉得自己遗漏了关键要点。


解决方法

问题核心在于:

  1. bake()默认仅输出建模相关变量(预测变量、结果变量),ID角色的列不会被自动包含;
  2. 即便ID列被意外包含,recipes默认会将字符型列转换为因子(基于训练集的水平),而测试集的ID值不在训练集水平范围内,因此被转为NA。

方法一:明确指定保留ID列并跳过预处理

通过step_skip()跳过对ID列的所有预处理,同时在bake()中明确指定要包含ID角色的列:

myRecipe <- recipe(mpg ~., data = training(myDataSplit)) %>%
  update_role(myID, new_role = "ID") %>%
  # 跳过对myID的预处理步骤
  step_skip(myID)

myTesting <- myRecipe %>%
  # 关闭字符型转因子的默认行为
  prep(strings_as_factors = FALSE) %>%
  # 明确包含建模变量与ID列
  bake(testing(myDataSplit), include = c(all_predictors(), all_outcomes(), all_roles("ID")))

方法二:配置ID角色的处理规则

使用update_role_requirements()设置ID列在训练阶段无需处理、在bake阶段需要保留,同时关闭字符转因子:

myRecipe <- recipe(mpg ~., data = training(myDataSplit)) %>%
  update_role(myID, new_role = "ID") %>%
  # 设置ID列:训练时不处理,bake时保留
  update_role_requirements(role = "ID", bake = TRUE, train = FALSE)

myTesting <- myRecipe %>%
  prep(strings_as_factors = FALSE) %>%
  bake(testing(myDataSplit))

补充说明

你使用workflow()的predict()时正常,是因为predict()默认仅返回预测结果,不会输出ID列,因此不会触发该问题。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 02:15:41