R语言按组无放回采样且最终结果无重复ID_2的实现问题
原代码的问题在于分组采样是每个ID_1组独立执行,没有全局的ID_2去重约束,因此会出现同一个对照ID被分配给多个原始参与者的情况。可以通过以下几种方案调整:
方案1:基础R循环实现(逻辑直观易调试)
核心逻辑是逐个遍历ID_1,每次选择当前ID_1对应的未被使用的ID_2,选完后将该ID_2加入全局禁用池,避免后续重复选择。
library(dplyr) # 提取所有唯一的原始参与者ID unique_id1 <- unique(df$ID_1) # 初始化结果存储、已使用ID池 match_result <- list() used_id2 <- c() for (id in unique_id1) { # 筛选当前ID_1可用的未被使用的对照ID available_id2 <- df %>% filter(ID_1 == id, !ID_2 %in% used_id2) %>% pull(ID_2) # 随机抽取1个对照ID selected_id2 <- sample(available_id2, size = 1) # 记录匹配结果 match_result[[as.character(id)]] <- df %>% filter(ID_1 == id, ID_2 == selected_id2) %>% slice(1) # 更新已使用ID池 used_id2 <- c(used_id2, selected_id2) } # 合并结果为数据框 final_match <- bind_rows(match_result)
- 逻辑清晰,可随时插入打印语句调试
- 可灵活扩展其他匹配约束,只需在filter中添加对应条件即可
方案2:tidyverse风格无循环实现
使用purrr::reduce实现迭代逻辑,无需显式写循环,代码更简洁:
library(dplyr) library(purrr) unique_id1 <- unique(df$ID_1) final_match <- reduce(unique_id1, function(res, curr_id) { used_id2 <- res$ID_2 curr_selected <- df %>% filter(ID_1 == curr_id, !ID_2 %in% used_id2) %>% slice_sample(n = 1) # dplyr 1.0.0+ 推荐替代sample_n的函数 bind_rows(res, curr_selected) }, .init = tibble())
前置检查说明
运行匹配代码前建议先做容量校验,避免因匹配池不足导致抽样失败:
# 检查每个ID_1的候选ID_2数量 df %>% group_by(ID_1) %>% summarise(candidate_cnt = n_distinct(ID_2)) # 全局校验:唯一对照ID总数必须大于等于原始参与者ID总数,才有可能实现无重复匹配 n_distinct(df$ID_2) >= n_distinct(df$ID_1)
内容的提问来源于stack exchange,提问作者George
相关产品推荐
相关产品推荐

