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

如何在tidymodels中为交叉验证每折单独预处理以避免数据泄露?

使用tidymodels避免交叉验证中的数据泄露:正确的预处理流水线构建

你当前的问题在于提前对全局训练数据执行了prep()和bake(),导致交叉验证的所有折都使用了全局统计量(均值、标准差)进行预处理,这会引入数据泄露。正确的做法是让每个交叉验证折的训练子集单独生成预处理规则,再应用到对应折的测试子集。

tidymodels提供了原生的工作流(workflow)机制,可以自动完成这个过程,无需手动处理每折的拆分和预处理,代码更简洁且符合最佳实践:

修正后的代码示例

library(tidyverse)
library(tidymodels)

set.seed(1000)

# 数据准备与初始分割
mtcars_sub <- mtcars %>% select(mpg, hp)
init_split <- initial_split(mtcars_sub, prop = 0.9)
train_data <- training(init_split)

# 1. 定义**未提前预处理**的recipe(不要调用prep())
preprocessing_recipe <- recipe(mpg ~ hp, data = train_data) %>%
  step_normalize(all_predictors())

# 2. 定义模型(以线性回归为例,可替换为你需要的模型)
lm_model <- linear_reg() %>%
  set_engine("lm") %>%
  set_mode("regression")

# 3. 创建workflow:整合预处理流程与模型
lm_workflow <- workflow() %>%
  add_recipe(preprocessing_recipe) %>%
  add_model(lm_model)

# 4. 对原始训练数据做交叉验证拆分(未经过预处理)
cv_folds <- vfold_cv(train_data, v = 3)

# 5. 运行交叉验证:自动为每折单独预处理
cv_results <- fit_resamples(
  object = lm_workflow,
  resamples = cv_folds,
  metrics = metric_set(rmse, rsq) # 可选:指定评估指标
)

关键说明

  • 不要提前调用prep():让fit_resamples()在每个交叉验证折内部自动对训练子集执行prep(),这样预处理的统计量完全基于该折的训练数据,避免泄露。
  • 使用workflow整合流程:workflow会自动处理预处理与模型训练的衔接,确保每折的测试子集使用对应训练子集生成的预处理规则进行转换。
  • 验证预处理效果:如果你想查看某折的预处理结果,可以用以下代码:
# 提取第一折的训练子集并应用该折的预处理规则
fold1_train <- analysis(cv_folds$splits[[1]])
fold1_recipe_prepped <- prep(preprocessing_recipe, data = fold1_train)
fold1_train_processed <- bake(fold1_recipe_prepped, new_data = fold1_train)

# 查看处理后hp的均值和标准差(应接近0和1)
fold1_train_processed %>% summarise(mean_hp = mean(hp), sd_hp = sd(hp))

为什么你的原始代码会出错?

你先对全局训练数据执行了prep()和bake(),再基于预处理后的数据做交叉验证拆分,这意味着每折的训练/测试子集已经用全局统计量缩放完毕,完全失去了交叉验证中"模拟真实数据流程"的意义——真实场景中你不可能用测试数据的统计量来预处理训练数据。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 23:22:48