R语言组内子组各类型等数量抽样失败:问题排查与修正
问题:分组下的等量抽样失败排查与修正
数据集与需求
我有一份按group(组)、subgroup(子组)、type(类型)划分的数据集,模拟代码如下:
data <- data.frame(group = sample(c(1:30), 10000, replace = TRUE), subgroup = sample(c(1:100), 10000, replace = TRUE), type = sample(c("A", "B"), 10000, replace = TRUE), value = sample(c(1:100), 10000, replace = TRUE))
需求是:在每个group+subgroup组合下,对type A和type B抽取等量样本,同时剔除group+subgroup+type组合中无数据(N=0)的情况。
我的尝试与问题
第一步:计算抽样量
library(tidyverse) n_to_sample <- data %>% group_by(group, subgroup, type) %>% summarise(n = n()) %>% pivot_wider(id_cols = c("group", "subgroup"), names_from = "type", values_from = "n") %>% rowwise() %>% mutate(lowestN = min(A, B)) %>% ungroup() %>% filter(!is.na(lowestN)) %>% select (group, subgroup, lowestN)
第二步:执行抽样
data_sampled <- data %>% left_join(n_to_sample, by = c("group", "subgroup")) %>% filter(!is.na(lowestN)) %>% arrange(group, type) %>% filter(row_number() %in% c(sample(which(type == "A"), mean(lowestN)), sample(which(type == "B"), mean(lowestN))), .by = c("group", "subgroup"))
验证代码与问题
我用以下代码验证抽样结果:
data %>% count(group, type, subgroup) %>% arrange(group, subgroup, type) %>% pivot_wider(id_cols = c("group", "subgroup"), names_from = "type", values_from = "n")
结果显示计数变量存在大量NA,说明抽样方案未成功。
错误分析与修正方案
核心错误点
- 验证对象错误:你用原数据集
data而非抽样后的data_sampled做验证,原数据本身就存在group+subgroup下仅包含A或仅包含B的情况,自然会出现NA,这不是抽样逻辑的问题。 - 抽样量计算错误:使用
mean(lowestN)会取所有组的抽样量均值,而非当前group+subgroup组合对应的lowestN,导致抽样数量不符合需求。 - 抽样逻辑混乱:
row_number() %in% sample(which(type == "A"), ...)的写法在分组内逻辑冲突,row_number()是整个group+subgroup组的行号,which(type == "A")是组内type为A的行位置,两者混用会导致抽样范围错误。
修正后的完整代码
步骤1:重新计算抽样量(简化逻辑)
n_to_sample <- data %>% count(group, subgroup, type) %>% pivot_wider(id_cols = c(group, subgroup), names_from = type, values_from = n) %>% filter(!is.na(A) & !is.na(B)) %>% # 直接过滤掉A/B缺失的组合 rowwise() %>% mutate(lowestN = min(A, B)) %>% ungroup() %>% select(group, subgroup, lowestN)
步骤2:正确执行抽样
data_sampled <- data %>% inner_join(n_to_sample, by = c("group", "subgroup")) %>% # 内连接自动过滤不符合的组合 group_by(group, subgroup, type) %>% slice_sample(n = first(lowestN)) %>% # 每个分组抽取对应数量的样本 ungroup()
正确的验证代码
# 验证每个group+subgroup下A和B的抽样数量是否相等 data_sampled %>% count(group, subgroup, type) %>% pivot_wider(id_cols = c(group, subgroup), names_from = type, values_from = n) %>% filter(A != B) # 结果为空则说明抽样正确
修正逻辑说明
- 用
inner_join替代left_join+filter,直接排除掉A/B缺失的group+subgroup组合,避免NA干扰。 - 用
slice_sample按group+subgroup+type分组抽样,逻辑更清晰,直接调用当前组的lowestN作为抽样数量。 - 验证时必须使用抽样后的
data_sampled,才能准确检查抽样结果是否符合要求。
内容的提问来源于stack exchange,提问作者BoTz
相关产品推荐
相关产品推荐

