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

如何用tidymodels结合网格搜索与单验证折调优KNN模型?

大数据集下用tidymodels实现单验证折的KNN网格搜索

问题描述

我刚学习KNN算法与机器学习,正在使用R语言的tidymodels进行练习。已掌握通过10折交叉验证实现网格搜索的代码:

hist_data_split <- initial_split(hist_data, strata = fraud)
hist_data_train <- training(hist_data_split)
hist_data_test <- testing(hist_data_split)
folds <- vfold_cv(hist_data_train, strata = fraud)
nearest_neighbor_grid <- grid_regular(neighbors(range = c(1, 500)), levels = 25)
knn_rec_1 <- recipe(fraud ~ ., data = hist_data_train)
knn_spec_1 <- nearest_neighbor(mode = "classification", engine = "kknn", neighbors = tune(), weight_func = "rectangular")
knn_wf_1 <- workflow(preprocessor = knn_rec_1, spec = knn_spec_1)
knn_fit_1 <- tune_grid(knn_wf_1, resamples = folds, metrics = metric_set(accuracy, sens, spec, roc_auc), control = control_resamples(save_pred = T), grid = nearest_neighbor_grid)

但hist_data数据量达169173,最优K值约为411,10折交叉验证调参耗时过长,提示改用单验证折替代交叉验证。尝试在vfold_cv中设置v=1时,R报错“At least one row should be selected for the analysis set”,想请教如何修改代码实现单验证折的网格搜索,是否可将tune_grid的resamples参数设为1?


解决方案

1. 报错原因

vfold_cv(v=1)会将训练集全部分配给验证集,导致训练子集为空,不符合模型训练的基本要求,因此触发报错。要实现单验证折,需要将训练集拆分为训练子集和独立验证子集,并使用tidymodels支持的验证集对象传入tune_grid。

2. 代码修改方案

以下两种方法都可以实现单验证折的网格搜索:

方法一:使用initial_validation_split快速创建验证集

# 保留原始数据集拆分逻辑
hist_data_split <- initial_split(hist_data, strata = fraud)
hist_data_train <- training(hist_data_split)
hist_data_test <- testing(hist_data_split)

# 将训练集进一步拆分为训练子集和验证子集(示例用8:2比例)
val_split <- initial_validation_split(hist_data_train, strata = fraud, prop = 0.8)
val_train <- training(val_split)
val_test <- testing(val_split)

# 创建符合tidymodels要求的验证集对象
val_set <- validation_set(val_split)

# 网格搜索部分仅需替换resamples参数为val_set
nearest_neighbor_grid <- grid_regular(neighbors(range = c(1, 500)), levels = 25)
knn_rec_1 <- recipe(fraud ~ ., data = val_train)
knn_spec_1 <- nearest_neighbor(mode = "classification", engine = "kknn", neighbors = tune(), weight_func = "rectangular")
knn_wf_1 <- workflow(preprocessor = knn_rec_1, spec = knn_spec_1)

knn_fit_1 <- tune_grid(knn_wf_1, 
                       resamples = val_set, 
                       metrics = metric_set(accuracy, sens, spec, roc_auc), 
                       control = control_resamples(save_pred = TRUE), 
                       grid = nearest_neighbor_grid)

方法二:手动构建验证集对象

如果需要自定义拆分逻辑,可以手动构建验证集对象:

# 原始数据集拆分
hist_data_split <- initial_split(hist_data, strata = fraud)
hist_data_train <- training(hist_data_split)
hist_data_test <- testing(hist_data_split)

# 手动拆分训练集为训练子集和验证子集
val_split <- initial_split(hist_data_train, strata = fraud, prop = 0.8)
val_train <- training(val_split)
val_test <- testing(val_split)

# 构建验证集对象
val_set <- tibble(
  splits = list(split(val_train, val_test)),
  id = "validation"
)

# 后续网格搜索代码与方法一完全一致

3. 关键注意事项

  • 不能直接将tune_grid的resamples参数设为1,该参数需要接受交叉验证对象或验证集对象,而非数值。
  • 拆分时始终保留strata = fraud,确保训练子集和验证子集的类别分布与原始数据集一致,避免数据偏差。
  • 单验证折的调参结果稳定性弱于交叉验证,确定最优K值后,建议使用整个训练集重新拟合模型,再在测试集上做最终评估。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 22:40:41