如何使用tidymodels处理分布在多列的同一分类变量?
tidymodels处理分散在多列的同分类变量方案
核心要求是同一分类取值无论出现在哪一列,模型效应完全一致,你设想的「宽转长-编码-聚合回单行」逻辑完全可行,且tidymodels的recipe框架完全支持这类操作,不需要跳出工作流做手动预处理(手动预处理会带来数据泄露风险)。以下是两种可直接复用的实现方式:
方案1:哑变量聚合(无自定义步骤,代码最简洁)
不需要做长宽转换,核心逻辑是先统一所有关联列的因子水平,编码后对同取值的哑变量做行聚合,完全满足同值同效应的要求:
- 先收集所有Pet列的全部非缺失取值,设为全局统一因子水平,避免某一列未出现某个取值导致水平缺失
- 对所有Pet列做全哑变量编码(不设基准水平)
- 按分类取值对哑变量列做行聚合:只要任意Pet列出现某个取值,对应聚合列就记为存在(或计数)
- 删除编码生成的中间列,保留聚合后的结果即可
可直接运行的示例代码:
library(tidymodels) # 构造示例数据集 df <- tibble( ID = 1:4, Pet_1 = c("dog", "cat", NA, "horse"), Pet_2 = c("horse", "bird", NA, "dog"), Pet_3 = c("cat", NA, NA, "snake"), Siblings = c(0,1,3,1), Income = c(90000,50000,75000,120000), Result = c(0,1,1,0) ) # 收集所有Pet列的全局取值 all_pet_levels <- unique(unlist(select(df, starts_with("Pet_"))) %>% na.omit()) pet_recipe <- recipe(Result ~ ., data = df) %>% # 标记ID列,不参与建模 update_role(ID, new_role = "ID") %>% # 统一所有Pet列的因子水平 step_mutate_at( starts_with("Pet_"), fn = ~factor(., levels = all_pet_levels) ) %>% # 对所有Pet列做独热编码 step_dummy(starts_with("Pet_"), one_hot = TRUE) %>% # 按宠物类型聚合哑变量:存在记为1,不存在记为0 step_mutate( across( all_of(paste0("Pet_1_", all_pet_levels)), ~ as.integer(rowSums(across(ends_with(paste0("_", cur_column() %>% str_extract("[a-z]+$")))), na.rm = T) > 0), .names = "contains_{.col %>% str_extract('[a-z]+$')}" ) ) %>% # 删除编码生成的中间列 step_rm(matches("^Pet_[1-3]_")) %>% # 常规后续预处理:数值变量标准化等 step_normalize(all_numeric_predictors(), -starts_with("contains_"), -Siblings) # 验证预处理结果 prep(pet_recipe) %>% bake(new_data = NULL)
运行后你会发现,无论dog出现在Pet_1还是Pet_2,contains_dog列都会正确标记为1,完全满足同值同效应的要求。如果需要统计饲养数量而非是否存在,把as.integer(>0)的判断去掉,直接保留rowSums的结果即可。三个Pet列全为NA的样本,所有contains_*列都会为0,自动对应「无宠物」分组,不需要额外插补缺失值。
方案2:自定义recipe步骤实现宽转长-编码-聚合
如果你更习惯长格式处理逻辑(比如需要对Pet变量做目标编码、权重编码等更复杂的编码操作),可以自定义recipe步骤完成全流程,所有计算都在recipe框架内完成,不会泄露测试集信息:
prep阶段:仅用训练集数据收集所有Pet列的合法取值,训练对应的编码器bake阶段:对任意传入的数据集(训练/测试/新数据),依次完成「选Pet列+ID转长格式→剔除缺失值→用预训练的编码器编码→按ID分组聚合编码结果→合并回原数据集还原单行结构」的操作- 聚合逻辑和方案1一致,同取值的编码结果会被合并到同一列,保证效应一致
关键注意点:绝对不要在定义recipe之前手动做Pet列的聚合和编码,否则交叉验证时测试集的取值会提前参与因子水平、编码参数的计算,导致模型评估结果虚高。所有预处理逻辑必须封装在recipe内部,由tidymodels工作流自动在每个交叉验证折的训练集上拟合参数,再应用到对应折的测试集上。
内容的提问来源于stack exchange,提问作者WTB
相关产品推荐
相关产品推荐

