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

如何将tidyverse链式处理转换为recipes包的预处理步骤?

在recipes建模流程中结合tidyverse分组操作

背景

我正在阅读Bradley Boehmke与Brandon Greenwell所著的《Hands-On Machine Learning with R》,书中推荐用recipes包搭建预处理流程。但我习惯先用tidyverse做数据探索(比如分组、过滤),而recipes的step_mutate不支持分组操作,想知道如何在建模流程中同时结合两者,这里以Kaggle的Spaceship Titanic数据集为例。

示例数据集

train <- structure(list(PassengerId = c("0001_01", "0002_01", "0003_01", 
"0003_02", "0004_01", "0005_01"), HomePlanet = c("Europa", "Earth", 
"Europa", "Europa", "Earth", "Earth"), CryoSleep = c("False", 
"False", "False", "False", "False", "False"), Cabin = c("B/0/P", 
"F/0/S", "A/0/S", "A/0/S", "F/1/S", "F/0/P"), Destination = c("TRAPPIST-1e", 
"TRAPPIST-1e", "TRAPPIST-1e", "TRAPPIST-1e", "TRAPPIST-1e", "PSO J318.5-22"
), Age = c(39, 24, 58, 33, 16, 44), VIP = c("False", "False", 
"True", "False", "False", "False"), RoomService = c(0, 109, 43, 
0, 303, 0), FoodCourt = c(0, 9, 3576, 1283, 70, 483), ShoppingMall = c(0, 
25, 0, 371, 151, 0), Spa = c(0, 549, 6715, 3329, 565, 291), VRDeck = c(0, 
44, 49, 193, 2, 0), Name = c("Maham Ofracculy", "Juanna Vines", 
"Altark Susent", "Solam Susent", "Willy Santantines", "Sandie Hinetthews"
), Transported = c("False", "True", "False", "False", "True", 
"True")), row.names = c(NA, 6L), class = "data.frame")

已有的tidyverse处理逻辑

我用dplyr实现了提取乘客组并计算组内人数的操作:

library(tidyverse)
library(recipes)

train2 <- train %>% 
  mutate(PassengerGroup = as.numeric(str_sub(PassengerId, 1, 4))) %>% 
  group_by(PassengerGroup) %>% 
    add_count(PassengerGroup, name = "PassengerGroupSize") %>% 
  ungroup()

recipes中遇到的局限

目前在recipes里只能完成第一步的变量提取,无法实现分组计数:

my_recipe <- recipe(Transported ~ ., data = train) %>%
  step_mutate(
    PassengerGroup = as.numeric(str_sub(PassengerId, 1, 4))
  )

可行方案

方案1:利用dplyr的.by参数直接实现分组计算

从dplyr 1.1.0版本开始,mutate支持.by参数,可直接指定分组变量,无需手动执行group_by/ungroup,这一特性可以直接在step_mutate中使用:

my_recipe <- recipe(Transported ~ ., data = train) %>%
  step_mutate(
    # 提取乘客组ID
    PassengerGroup = as.numeric(str_sub(PassengerId, 1, 4)),
    # 按乘客组分组计算组内人数
    PassengerGroupSize = n(),
    .by = PassengerGroup
  )

# 验证处理结果
prepped_recipe <- prep(my_recipe)
baked_data <- bake(prepped_recipe, new_data = train)

处理后的baked_data与tidyverse链式处理的train2结果完全一致。

方案2:自定义recipes步骤封装复杂分组逻辑

如果需要处理更复杂的分组操作(比如嵌套变换、多步骤分组计算),可以自定义一个recipes步骤来封装整个tidyverse流程:

1. 定义数据处理函数

custom_group_process <- function(data) {
  data %>%
    mutate(PassengerGroup = as.numeric(str_sub(PassengerId, 1, 4))) %>%
    group_by(PassengerGroup) %>%
    add_count(name = "PassengerGroupSize") %>%
    ungroup()
}

2. 创建并使用自定义步骤

# 注册自定义步骤
step_custom_group <- function(recipe, ...) {
  step(
    recipe,
    operation = function(x, ...) custom_group_process(x),
    trained = FALSE,
    inputs = NULL,
    ...
  )
}

# 在recipe中调用自定义步骤
my_recipe <- recipe(Transported ~ ., data = train) %>%
  step_custom_group()

# 验证结果
prepped_recipe <- prep(my_recipe)
baked_data <- bake(prepped_recipe, new_data = train)

这种方式可以灵活整合任意复杂的tidyverse数据处理逻辑到recipes流程中。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 21:30:54