使用perry包对嵌套奶牛数据做分组10折交叉验证的折分配问题
解决按奶牛ID分组的10折交叉验证折分配问题
问题根源排查
出现部分观测Fold值为0的核心原因,大概率是BTN1列存在格式问题(如数值型ID、NA值),或是cvFolds的grouping参数输入不符合要求。
解决方案
方案1:预处理ID列后重新调用cvFolds
- 确保
BTN1为因子/字符类型(避免数值型ID被误判):
# 检查ID列类型 str(df$BTN1) # 若为数值型,转换为因子 df$BTN1 <- as.factor(df$BTN1)
- 检查并清理NA值:
# 统计NA数量 sum(is.na(df$BTN1)) # 删除含NA的观测(或根据业务逻辑补全) df <- df[!is.na(df$BTN1), ]
- 正确调用
cvFolds,grouping参数传入全量观测对应的BTN1向量:
library(perry) set.seed(123) # 固定随机种子保证结果可重复 cv_result <- cvFolds(nrow(df), K = 10, grouping = df$BTN1) # 将折号映射回原数据集 df$Fold <- cv_result$which
方案2:手动生成分组折号(更稳定可控)
如果cvFolds的分组逻辑仍有问题,可手动实现按ID分配折号:
- 提取所有唯一奶牛ID:
unique_btns <- unique(df$BTN1)
- 给唯一ID分配10折(支持按农场分层抽样,适配嵌套结构):
set.seed(123) # 基础分配:均匀拆分ID到10折 fold_ids <- sample(rep(1:10, length.out = length(unique_btns))) # 若需按农场分层:先按农场分组,再在每个农场内拆分ID # fold_ids <- df %>% distinct(BTN1, farm_id) %>% group_by(farm_id) %>% mutate(Fold = sample(rep(1:10, length.out = n()))) %>% pull(Fold)
- 建立ID与折号的映射关系,合并回原数据集:
fold_map <- data.frame(BTN1 = unique_btns, Fold = fold_ids) df <- merge(df, fold_map, by = "BTN1", all.x = TRUE)
关键注意事项
cvFolds的grouping参数必须是与观测行数一致的向量,每个元素对应当前观测的分组ID,不能只传入唯一ID列表- 同一奶牛的所有观测会被分配到同一折,彻底避免信息泄露
内容的提问来源于stack exchange,提问作者ILo
相关产品推荐
相关产品推荐

