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

使用caret结合recipes训练模型报错:$ operator is invalid for atomic vectors

解决caret搭配recipes训练模型时的"$ operator is invalid for atomic vectors"错误

我刚帮你排查了这个问题,核心原因是你手动传入的交叉验证索引和recipes在caret中的运行逻辑不兼容。当用rsample2caret()把rsample的折叠转成caret格式后直接丢给trainControl,会导致recipes在动态处理数据时,错误地拿到了原子向量而非预期的数据结构,从而抛出这个$运算符无效的错误。

给你两个可行的修复方案:

方案一:让caret自动管理交叉验证(推荐)

这个方案最简单,不需要手动生成和传递索引,让caret和recipes自动配合,完全避免结构不兼容的问题:

library(caret)
library(tidymodels)
library(embed)
library(doParallel)

# 初始化并行集群
cluster <- makeCluster(detectCores() - 1)
registerDoParallel(cluster)

# 预处理数据,把cyl转成因子型
df <- mtcars %>% as_tibble() %>% mutate(cyl = factor(cyl)) 

set.seed(123)
cv_split <- initial_split(df)
df_train <- training(cv_split)

# 定义交叉验证控制参数,直接用caret的参数设置10折重复10次
set.seed(123)
ctrl <- trainControl(
  method = "repeatedcv", 
  number = 10,  # 对应原来vfold_cv的v=10
  repeats = 10, 
  allowParallel = TRUE)

# 定义你的recipe流程
rec <- recipe(mpg ~ ., data = df_train) %>% 
  step_nzv(all_predictors()) %>% 
  step_lencode_mixed(all_nominal(), outcome = vars(mpg))

# 训练模型,这次不用手动传索引啦
train(rec, data = df_train, method = "glmnet", tuneLength = 20, trControl = ctrl)

方案二:如果必须用自定义折叠(预处理recipe后再训练)

要是你一定要用rsample生成的特定交叉验证折叠,那可以先把recipe预处理完成,得到处理好的训练数据,再传给caret的train():

library(caret)
library(tidymodels)
library(embed)
library(doParallel)

cluster <- makeCluster(detectCores() - 1)
registerDoParallel(cluster)

df <- mtcars %>% as_tibble() %>% mutate(cyl = factor(cyl)) 

set.seed(123)
cv_split <- initial_split(df)
df_train <- training(cv_split)

# 先定义并预处理recipe
rec <- recipe(mpg ~ ., data = df_train) %>% 
  step_nzv(all_predictors()) %>% 
  step_lencode_mixed(all_nominal(), outcome = vars(mpg))
prepped_rec <- prep(rec, training = df_train)
train_data <- bake(prepped_rec, new_data = df_train)

# 生成自定义交叉验证索引
set.seed(123)
cv_folds <- vfold_cv(df_train, v = 10, repeats = 10)
cv_ind <- rsample2caret(cv_folds)

# 设置控制参数并训练
ctrl <- trainControl(
  method = "repeatedcv", 
  repeats = 10, 
  index = cv_ind$index, 
  indexOut = cv_ind$indexOut, 
  allowParallel = TRUE)

train(x = train_data %>% select(-mpg), y = train_data$mpg, method = "glmnet", tuneLength = 20, trControl = ctrl)

为什么原来的代码会报错?

简单说,当你把手动生成的index传入trainControl后,caret在交叉验证过程中,会对每个折叠的子集应用recipe,但这个子集的结构在recipe处理时被转换成了原子向量(而非数据框),导致后续代码试图用$访问列时出错。上面两个方案要么让caret自动处理折叠和recipe的配合,要么先把recipe处理完再用干净的数据框训练,都能避开这个结构冲突。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:44:57