使用dplyr实现带最小样本量约束的分层比例分配抽样
实现带最小样本约束的比例分配分层抽样(dplyr版)
要实现你需求的「比例分配抽样+每个层至少抽1个样本」,我们可以把计算逻辑和抽样步骤整合到dplyr的管道操作里,一步到位。下面是完整的解决方案:
完整代码示例
library(dplyr) set.seed(123) # 设置随机种子,确保结果可重复 # 构造你的原始数据 var = c(rep("A",10),rep("B",10),rep("C",3),rep("D",5),"E","F") value = rnorm(30) dat = tibble(var, value) # 执行带约束的比例分配抽样 sampled_dat <- dat %>% group_by(var) %>% # 1. 计算每个层的大小、权重,以及目标样本量 mutate( ni = n(), # 当前层的总体数量 weight = ni / nrow(dat), # 层权重(ni/总总体量) target_sample = pmax(ni * weight, 1) %>% round() # 计算目标样本量,小于1则设为1,再转整数 ) %>% # 2. 按调整后的目标样本量在每层抽样 slice_sample(n = first(target_sample)) %>% # 3. 清理结果,保留需要的列并取消分组 ungroup() %>% select(var, value) # 查看抽样结果 sampled_dat
代码分步解释
分组与基础计算:
group_by(var):按你的层变量var分组,针对每个层单独处理。ni = n():获取当前层的总体数量。weight = ni / nrow(dat):计算每个层的权重(层大小/总体总量),这是比例分配的核心依据。
目标样本量调整:
pmax(ni * weight, 1):用pmax函数确保计算出的样本量(ni * weight)如果小于1,就自动替换为1,满足你「至少抽1个样本」的约束。%>% round():把计算出的非整数样本量转为整数(毕竟抽样数量必须是整数;如果需要向上取整可以用ceiling,向下取整用floor,根据你的需求调整即可)。
抽样与结果清理:
slice_sample(n = first(target_sample)):dplyr的slice_sample专门用于抽样,这里取每个组的第一个target_sample值(因为同组内该值都相同)作为抽样数量。ungroup():可选操作,取消分组让结果更整洁;select(var, value)保留你需要的列,去掉中间计算的辅助列。
抽样结果验证
按照你的数据结构,最终每个层的抽样数量会是:
- A层:3个(10*(10/30)≈3.33,取整为3)
- B层:3个(同A层)
- C层:1个(3*(3/30)=0.3,触发最小样本约束)
- D层:1个(5*(5/30)≈0.83,触发最小样本约束)
- E/F层:各1个(都触发最小样本约束)
这样既满足了比例分配的要求,又保证了小层不会被遗漏。
内容的提问来源于stack exchange,提问作者Homer Jay Simpson
相关产品推荐
相关产品推荐

