dplyr sample_n из одной группы - PullRequest
1 голос
/ 20 февраля 2020

У меня есть некоторые данные, где сводка количества наблюдений выглядит следующим образом:

# A tibble: 14 x 3
# Groups:   status [2]
   status  year     n
    <dbl> <dbl> <int>
 1      0  2010  4593
 2      0  2011 10990
 3      0  2012 27711
 4      0  2013 99989
 5      0  2014 95407
 6      0  2015 89010
 7      0  2016 72289
 8      1  2010   584
 9      1  2011   785
10      1  2012   640
11      1  2013   667
12      1  2014   377
13      1  2015   460
14      1  2016   104

Где класс одной группы значительно выше, чем класс другой группы. Как можно случайным образом отобрать класс 0, не делая ничего для класса 1. То есть я хотел бы сохранить все наблюдения класса 1 и случайным образом отобрать наблюдения класса 0 к 4593 году (что является минимальным количеством наблюдений за этот год )

Использование group_by(status, year), а затем sample_n() не работает, поскольку значение 4593 больше, чем значения в группе класса 1.

Некоторая случайная выборка моих данных:

    structure(list(status = c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1), 
    year = c(2013, 2014, 2012, 2013, 2016, 2013, 2015, 2014, 
    2013, 2016, 2015, 2016, 2011, 2014, 2016, 2012, 2013, 2012, 
    2014, 2014, 2012, 2012, 2012, 2016, 2016, 2012, 2016, 2015, 
    2013, 2014, 2015, 2013, 2015, 2015, 2014, 2015, 2011, 2014, 
    2013, 2012, 2011, 2016, 2015, 2015, 2015, 2014, 2012, 2013, 
    2015, 2012, 2015, 2016, 2015, 2013, 2014, 2014, 2014, 2013, 
    2013, 2016, 2016, 2013, 2015, 2012, 2014, 2014, 2013, 2015, 
    2014, 2016, 2016, 2014, 2012, 2016, 2013, 2010, 2011, 2014, 
    2016, 2013, 2016, 2014, 2014, 2013, 2013, 2013, 2016, 2016, 
    2012, 2014, 2013, 2015, 2016, 2013, 2013, 2015, 2013, 2014, 
    2013, 2015, 2013, 2013, 2011, 2014, 2016, 2013, 2010, 2012, 
    2014, 2012, 2011, 2011, 2013, 2015, 2014, 2010, 2010, 2013, 
    2010, 2014, 2011, 2011, 2014, 2013, 2014, 2015, 2015, 2013, 
    2014, 2013, 2011, 2013, 2014, 2013, 2011, 2013, 2012, 2015, 
    2012, 2012, 2012, 2010, 2013, 2013, 2011, 2011, 2011, 2012, 
    2016, 2013, 2011, 2011, 2012, 2012, 2014, 2010, 2013, 2014, 
    2011, 2012, 2010, 2012, 2012, 2011, 2015, 2011, 2011, 2013, 
    2015, 2010, 2015, 2011, 2015, 2015, 2012, 2012, 2013, 2012, 
    2014, 2014, 2012, 2012, 2014, 2010, 2011, 2013, 2014, 2012, 
    2013, 2016, 2014, 2012, 2012, 2013, 2010, 2012, 2013, 2014, 
    2014, 2011)), groups = structure(list(status = c(0, 1), .rows = structure(list(
    1:100, 101:200), ptype = integer(0), class = c("vctrs_list_of", 
"vctrs_vctr"))), row.names = c(NA, -2L), class = c("tbl_df", 
"tbl", "data.frame"), .drop = TRUE), row.names = c(NA, -200L), class = c("grouped_df", 
"tbl_df", "tbl", "data.frame"))

1 Ответ

2 голосов
/ 20 февраля 2020

Я думаю, это будет работать. dat - ваш пример фрейма данных. Приведенный ниже код разбивает фрейм данных на status, а затем использует imap для оценки необходимости выборки. Если имя элемента списка "0", оно будет проводить выборку. Вы можете изменить size = 1 на минимальное количество вашего реального фрейма данных.

library(dplyr)
library(purrr)

dat2 <- dat %>%
  split(f = .$status) %>%
  imap(function(x, y){
    if (y %in% "0"){
      x <- x %>% 
        group_by(status, year) %>%
        sample_n(size = 1) 
    }
    return(x)
  }) %>%
  bind_rows()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...