R语言数据集拆分:无重叠ID且各集含全目标类的训练/验证/测试集构建
解决方案
核心思路是按目标类别(var2)分层,对每个类别下的独立ID进行比例分配,既能保证每个集合包含所有类别,又能确保同一ID仅出现在一个集合中,同时精准控制拆分比例。
实现步骤
- 提取每个ID对应的唯一类别(默认每个ID的
var2是统一的,示例数据符合此特征) - 按
var2分组,对每组内的ID按指定比例分配到训练、验证、测试集 - 将分组结果关联回原数据集
代码实现
library(dplyr) # 定义拆分比例 train_prop <- 0.7 val_prop <- 0.2 test_prop <- 0.1 # 1. 获取每个ID对应的唯一类别并去重 id_class <- data %>% select(IDs, var2) %>% distinct(IDs, .keep_all = TRUE) # 2. 按类别分层分配ID到不同集合 set.seed(123) # 设置随机种子保证结果可复现 id_assignments <- id_class %>% group_by(var2) %>% mutate( # 计算每组内各集合应分配的ID数量 n_total = n(), n_train = floor(n_total * train_prop), n_val = floor(n_total * val_prop), # 按顺序分配分组:先训练集,再验证集,剩余为测试集 Group = case_when( row_number() <= n_train ~ "training", row_number() <= n_train + n_val ~ "validation", TRUE ~ "test" ) ) %>% ungroup() %>% select(IDs, Group) # 保留ID与分组的对应关系 # 3. 将分组关联回原数据集 split_data <- data %>% left_join(id_assignments, by = "IDs")
结果验证
可以通过以下代码确认拆分是否符合要求:
# 检查是否存在同一ID跨集合的情况(应返回空表) split_data %>% group_by(IDs) %>% summarise(n_groups = n_distinct(Group)) %>% filter(n_groups > 1) # 检查每个集合是否包含所有类别 split_data %>% group_by(Group, var2) %>% summarise(sample_count = n()) %>% tidyr::pivot_wider(names_from = var2, values_from = sample_count) # 检查ID层面的拆分比例是否符合预期 split_data %>% distinct(IDs, .keep_all = TRUE) %>% count(Group) %>% mutate(actual_prop = n / sum(n))
关键优势
- ID无重叠:基于独立ID分配分组,确保同一ID的所有样本进入同一个集合
- 类别全覆盖:按
var2分层处理,每个类别下的ID都会分配到三个集合,最终每个集合必然包含所有目标类别 - 比例精准:对每个类别内的ID按比例计算分配数量,避免随机抽样导致的比例偏差(若需更严格比例,可微调最后剩余ID的分配逻辑)
特殊情况处理
如果某个类别下的ID数量过少(比如不足3个),无法满足每个集合都有该类别的ID,可选择:
- 合并相似小类别
- 微调拆分比例
- 过滤掉这类小样本ID(符合题目允许数据集缩减的要求)
内容的提问来源于stack exchange,提问作者ksrm
相关产品推荐
相关产品推荐

