如何在R中对多观测行的ID进行有放回随机抽样(Bootstrap)
基于ID的有放回抽样,确保总观测数恰好为指定值
给定如下数据:
Var1 IDvar 123 1 456 2 789 2 987 3 希望基于
IDvar进行有放回抽样,最终得到恰好4个观测。直接抽样IDvar会拆分同一ID的行(比如只抽中ID2的某一行);而抽样唯一ID时,又可能出现总观测数超出指定值的情况(比如抽中ID3、1、1、2,总观测数为1+1+1+2=5)。
高效实现方法
我们可以通过迭代抽样的方式,每次只选择行数不超过剩余所需样本量的ID,确保总观测数最终恰好等于目标值。以下是R语言的具体实现:
步骤1:定义数据
df <- data.frame( Var1 = c(123, 456, 789, 987), IDvar = c(1, 2, 2, 3) )
步骤2:实现抽样函数
sample_by_id <- function(df, id_col, n) { # 统计每个ID对应的行数 id_counts <- table(df[[id_col]]) remaining <- n selected_ids <- c() while (remaining > 0) { # 筛选出当前可选择的ID(行数不超过剩余样本量) eligible_ids <- names(id_counts)[id_counts <= remaining] if (length(eligible_ids) == 0) { stop("无法达到指定样本量:所有ID的行数均大于剩余需要的样本量") } # 有放回随机抽取一个ID chosen_id <- sample(eligible_ids, 1, replace = TRUE) selected_ids <- c(selected_ids, chosen_id) # 更新剩余所需样本量 remaining <- remaining - id_counts[chosen_id] } # 根据选中的ID重复提取对应行 result <- do.call(rbind, lapply(selected_ids, function(id) { df[df[[id_col]] == id, ] })) return(result) }
步骤3:调用函数
# 抽取4个观测 set.seed(123) # 设置随机种子保证结果可复现 sampled_df <- sample_by_id(df, "IDvar", 4) print(sampled_df)
示例输出(因随机抽样可能不同):
Var1 IDvar 1 123 1 2 456 2 3 789 2 4 123 1
关于逐个抽样检查思路的效率评价
你提出的“逐个抽样ID并检查剩余样本量”的思路是完全可行的,且实际效率并不低:
- 每次循环仅需执行简单的筛选和抽样操作,循环次数最多等于目标样本量(最坏情况每次选择行数为1的ID),但大多数场景下循环次数远小于目标值;
- 相比拒绝抽样(反复生成整批ID直到总行数符合要求),这种方法更稳定,不会出现连续多次抽样失败的情况;
- 代码逻辑清晰,易于理解和维护,对于绝大多数实际数据规模来说,性能开销可以忽略。
内容的提问来源于stack exchange,提问作者Aku-Ville Lehtimäki
相关产品推荐
相关产品推荐

