使用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
相关产品推荐
相关产品推荐

