对每组的一部分进行抽样,但具有最小约束(使用 dplyr)

Sample a proportion of each group, BUT with a minimum constraint (using dplyr)

我有 6 个类别(层)的人口,我想在每个层中取 10% 作为样本。这样做我采取:

var = c(rep("A",10),rep("B",10),rep("C",3),rep("D",5),"E","F");var
value = rnorm(30)
dat = tibble(var,value);
pop=dat%>%group_by(var)
pop
singleallocperce = slice_sample(pop, prop=0.1);
singleallocperce

结果:

# A tibble: 2 x 2
# Groups:   var [2]
  var   value
  <chr> <dbl>
1 A     -1.54
2 B     -1.12

但我想即使在某些层中,它们内部的 polupation 不能达到 10% 的采样率,至少要采取一个 observation.How 我可以在 R 中使用 dplyr 包做到这一点吗?

这是一个可能的解决方案:

sample_func <- function(data) {
  standard <- data %>% 
    group_by(var) %>% 
    slice_sample(prop = 0.1) %>% 
    ungroup()
  
  if(!all(unique(data$var) %in% unique(standard$var))) {
    mins <- data %>% 
      filter(!var %in% standard$var) %>% 
      group_by(var) %>% 
      slice(1) %>% 
      ungroup()
  }
  
  bind_rows(standard, mins) 
  
}

sample_func(dat)

给出:

  var     value
  <chr>   <dbl>
1 A      1.36  
2 B     -1.03  
3 C     -0.0450
4 D     -0.380 
5 E     -0.0556
6 F      0.519 

假设是,如果您按比例抽样并且 var 没有任何样本,则最小阈值将从 var 中抽取一条记录(通过使用 slice(1) ).

可能的方法(注意 20 x A 的存在以检查是否返回了两个)。

library(tidyverse)

# Data (note 20 As)
var = c(rep("A",20),rep("B",10),rep("C",3),rep("D",5),"E","F")
value = rnorm(40)
dat = tibble(var, value)

# Possible approach
dat %>%
  group_by(var) %>%
  mutate(min = if_else(n() * 0.1 >= 1, n() * 0.1, 1),
         random = sample(n())) %>%
  filter(random <= min) |> 
  select(var, value)
#> # A tibble: 7 × 2
#> # Groups:   var [6]
#>   var     value
#>   <chr>   <dbl>
#> 1 A      0.0105
#> 2 A      0.171 
#> 3 B     -1.89  
#> 4 C      1.89  
#> 5 D      0.612 
#> 6 E      0.516 
#> 7 F      0.185

reprex package (v2.0.1)

创建于 2022-06-02

data.table

library(data.table)

setDT(dat) # make the tibble a data.table

dat[, .SD[sample((1:.N), fifelse(.N >= 10, .N %/% 10, 1))], var]

结果

   var     value
1:   A -0.040487
2:   A  0.543354
3:   B -1.100892
4:   C  0.998006
5:   D  0.496898
6:   E  0.819967
7:   F  0.629236

数据

# Data (note 20 As)
var = c(rep("A",20),rep("B",10),rep("C",3),rep("D",5),"E","F")
value = rnorm(40)
dat = tibble(var, value)