простая случайная выборка из групп с заданным размером выборки

#r

#r

Вопрос:

Итак, у меня есть фрейм данных (my.df), который я сгруппировал по переменной «strat». Каждая строка состоит из множества переменных. Пример того, как это выглядит, приведен ниже — я упростил свой файл .df для этого примера, поскольку он довольно большой. Что я хочу сделать дальше, так это нарисовать простую случайную выборку из каждой группы. Если бы я хотел сделать 5 наблюдений из каждой группы, я бы использовал этот код:

 new_df <- my.df %>% group_by(strat) %>% sample_n(5)
 

Однако у меня есть другой указанный размер выборки, который я хочу использовать для выборки для каждой группы. У меня есть эти размеры выборки в векторе nj.

 nj <- c(3, 4, 2)
 

Поэтому в идеале я хотел бы получить 3 наблюдения из моих первых слоев, 4 наблюдения из моих вторых слоев и 2 наблюдения из моего последнего srata. Я не уверен, смогу ли я выполнять выборку по группам, используя каждый уникальный размер выборки (без необходимости выписывать «образец» столько раз, сколько мне нужно)? Заранее спасибо!

мой файл .df выглядит так:

 var1  var2  strat
15     3     1
13     5     3
8      6     2
12     70    3
11     10    1
14     4     2
 

Комментарии:

1. my.df[sort(unlist(mapply(sample, split(1:nrow(my.df), my.df$strat), pmin(nj,lengths(split(1:nrow(my.df), my.df$strat)))))), ] должно сработать.

Ответ №1:

Вы можете использовать stratified из моего пакета «splitstackshape».

Вот некоторые примеры данных:

 set.seed(1)
my.df <- data.frame(var1 = sample(100, 20, TRUE),
                    var2 = runif(20),
                    strat = sample(3, 20, TRUE))
table(my.df$strat)
# 
# 1 2 3 
# 5 9 6 
 

Вот как вы можете использовать stratified :

 library(splitstackshape)
# nj needs to be a named vector
nj <- c("1" = 3, "2" = 4, "3" = 2)
stratified(my.df, "strat", nj)
#    var1      var2 strat
# 1:   72 0.7942399     1
# 2:   39 0.1862176     1
# 3:   50 0.6684667     1
# 4:   21 0.2672207     2
# 5:   69 0.4935413     2
# 6:   91 0.1255551     2
# 7:   78 0.4112744     2
# 8:    7 0.3403490     3
# 9:   27 0.9347052     3

table(.Last.value$strat)
# 
# 1 2 3 
# 3 4 2 
 

Ответ №2:

Поскольку ваших данных недостаточно для выборки, давайте рассмотрим этот пример на iris dataset

 library(tidyverse)

nj <- c(3, 5, 6)
set.seed(1)
iris %>% group_split(Species) %>% map2_df(nj, ~sample_n(.x, size = .y))

# A tibble: 14 x 5
   Sepal.Length Sepal.Width Petal.Length Petal.Width Species   
          <dbl>       <dbl>        <dbl>       <dbl> <fct>     
 1          4.6         3.1          1.5         0.2 setosa    
 2          4.4         3            1.3         0.2 setosa    
 3          5.1         3.5          1.4         0.2 setosa    
 4          6           2.7          5.1         1.6 versicolor
 5          6.3         2.5          4.9         1.5 versicolor
 6          5.8         2.6          4           1.2 versicolor
 7          6.1         2.9          4.7         1.4 versicolor
 8          5.8         2.7          4.1         1   versicolor
 9          6.4         2.8          5.6         2.2 virginica 
10          6.9         3.2          5.7         2.3 virginica 
11          6.2         3.4          5.4         2.3 virginica 
12          6.9         3.1          5.1         2.3 virginica 
13          6.7         3            5.2         2.3 virginica 
14          7.2         3.6          6.1         2.5 virginica 
 

Ответ №3:

Вы можете привести nj значения к выборке в dataframe, а затем использовать sample_n по группам.

 library(dplyr)

df %>%
  mutate(nj = nj[strat]) %>%
  group_by(strat) %>%
  sample_n(size = min(first(nj), n()))
 

Обратите внимание, что приведенное выше работает, поскольку strat имеет значение 1, 2, 3. Для общего решения, когда группа не имеет таких значений, вы можете использовать :

 df %>%
  mutate(nj = nj[match(strat, unique(strat))]) %>%
  group_by(strat) %>%
  sample_n(size = min(first(nj), n()))
 

Комментарии:

1. Вы уверены? Если я изменю ваше nj значение на nj <- c(3, 1, 1) . Для данных, которыми вы поделились, он выбирает 2 строки для strat = 1, 1 для strat = 2 и 1 для strat = 3, что, как я полагаю, ожидается. Это ничего не должно менять, но если это сбивает с толку, измените nj какое-либо другое имя в dataframe.