You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何按分组变量抽取无重复item_type的数据框随机样本?

带约束条件的抽样问题

第一个示例数据与需求

我有如下结构的tibble数据框:

dat <- tibble(
  item_type  = rep(1:36, each = 6), 
  condition1 = rep(c("a", "b", "c"), times = 72), 
  condition2 = rep(c("y", "z"), each = 3, times = 36), 
) %>% 
  unite(unique, item_type, condition1, condition2, sep = "-", remove = F)

数据框内容预览:

# A tibble: 216 × 4
   unique item_type condition1 condition2
   <chr>      <int> <chr>      <chr>     
 1 1-a-y          1 a          y         
 2 1-b-y          1 b          y         
 3 1-c-y          1 c          y         
 4 1-a-z          1 a          z         
 5 1-b-z          1 b          z         
 6 1-c-z          1 c          z         
 7 2-a-y          2 a          y         
 8 2-b-y          2 b          y         
 9 2-c-y          2 c          y         
10 2-a-z          2 a          z    

我需要抽取36行随机样本,要求满足两个条件:

  • 每个condition1与condition2的组合恰好出现6次
  • 所有样本的item_type完全不重复

一开始尝试用slice_sample()按分组抽样:

set.seed(1)
dat %>% 
  slice_sample(n = 6, by = c("condition1", "condition2")) %>% 
  count(condition1, condition2)

统计结果显示各组合确实都出现了6次:

condition1 condition2     n
  <chr>      <chr>      <int>
1 a          y              6
2 a          z              6
3 b          y              6
4 b          z              6
5 c          y              6
6 c          z              6

但进一步检查发现,抽样结果里的item_type存在重复:

set.seed(1)
dat %>% 
  slice_sample(n = 6, by = c("condition1", "condition2")) %>% 
  count(item_type) %>% 
  arrange(desc(n))

统计结果如下:

# A tibble: 22 × 2
   item_type     n
       <int> <int>
 1        10     3
 2        34     3
 3         1     2
 4         6     2
 5         7     2
 6        15     2
 7        20     2
 8        21     2
 9        23     2
10        25     2
# … with 12 more rows

请问能不能只用slice_sample()实现满足所有条件的抽样?


补充的第二个示例数据

还有另一个结构的数据框:

dat <- tibble(
  item_type  = rep(1:36, each = 3), 
  condition1 = rep(c("a", "b"), each = 54), 
  condition2 = rep(c("x", "y", "z"), times = 36), 
) %>% 
  unite(unique, item_type, condition1, condition2, sep = "-", remove = F)

数据预览:

# A tibble: 108 × 4
   unique item_type condition1 condition2
   <chr>      <int> <chr>      <chr>     
 1 1-a-x          1 a          x         
 2 1-a-y          1 a          y         
 3 1-a-z          1 a          z         
 4 2-a-x          2 a          x         
 5 2-a-y          2 a          y         
 6 2-a-z          2 a          z         
 7 3-a-x          3 a          x         
 8 3-a-y          3 a          y         
 9 3-a-z          3 a          z         
10 4-a-x          4 a          x    

我试过用以下代码抽样,但结果不符合各组合的计数要求:

inner_join(
  dat, 
  distinct(dat,condition1, condition2) %>% 
    uncount(n()) %>% 
    mutate(item_type = sample(n()))
) 

生成的数据框长度为20,各组合计数如下:

condition1 condition2     n
  <chr>      <chr>      <int>
1 a          x              4
2 a          y              4
3 a          z              4
4 b          x              3
5 b          y              4
6 b          z              5

解决方案

针对第一个示例的需求

单独用slice_sample()没法实现,因为它是按condition1+condition2分组独立抽样,不同组之间不会规避重复的item_type。要同时满足两个约束,得换思路:

我们可以先构建一个符合要求的item_type与条件组合的映射,再和原数据关联:

set.seed(1)
# 先列出所有需要的条件组合(每个组合6次)
required_pairs <- expand_grid(
  condition1 = c("a", "b", "c"),
  condition2 = c("y", "z")
) %>% 
  uncount(6)

# 随机分配不重复的item_type给这些组合
sampled_map <- required_pairs %>% 
  mutate(item_type = sample(unique(dat$item_type), n()))

# 关联原数据得到最终样本
final_sample <- inner_join(dat, sampled_map, by = c("item_type", "condition1", "condition2"))

# 验证条件
final_sample %>% count(condition1, condition2) # 每个组合6次
final_sample %>% count(item_type) %>% filter(n>1) # 无重复item_type

针对第二个示例的调整

假设需求是每个condition1+condition2组合抽取相同次数(比如每个组合6次,共6*6=36行,且item_type不重复),可以用类似逻辑:

set.seed(1)
# 定义每个组合需要的抽样数量
sample_per_pair <- 6
required_pairs <- expand_grid(
  condition1 = unique(dat$condition1),
  condition2 = unique(dat$condition2)
) %>% 
  uncount(sample_per_pair)

# 分配不重复的item_type
sampled_map <- required_pairs %>% 
  mutate(item_type = sample(unique(dat$item_type), n()))

final_sample <- inner_join(dat, sampled_map, by = c("item_type", "condition1", "condition2"))

如果需求是其他计数比例,只需要调整uncount()里的数值即可,核心是先构建满足计数和唯一性的映射,再关联原数据。


内容的提问来源于stack exchange,提问作者babylinguist

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 06:28:01