Подмножество n строк каждого уровня на основе уровня с меньшим количеством строк - PullRequest
0 голосов
/ 01 ноября 2018

Представьте, что у меня есть некоторый фрейм данных с определенным количеством уровней:

    x1    x2  ...  xi   Level
1    1     1        1       A    
2    2     2        4       A
3    1     4        2       B
.    .     .        .       B 
.    .     .        .       B
.    .     .        .       C
.    .     .        .       C
.    .     .        .       C

Я пытаюсь установить подкадр данных таким образом, чтобы на всех уровнях было n строк, где n - количество строк уровня с меньшим количеством экземпляров. В приведенном выше примере A - это менее заполненный уровень (2 строки), поэтому желаемый результат:

    x1    x2  ...  xi   Level
1    1     1        1       A    
2    2     2        4       A
3    1     4        2       B
.    .     .        .       B
.    .     .        .       C
.    .     .        .       C

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

    x1    x2  ...  xi   Level
1    1     1        1       A    
.    .     .        .       .
.    .     .        .       .
.    .     .        .       .
10   1     2        3       C  
11   3     2        1       C  
12   2     1        3       C  
13   3     1        2       C  
14   2     3        1       C

и n = 3, я бы хотел не выбирать первые 3 строки уровня C (10,11,12). Заранее спасибо.

Ответы [ 4 ]

0 голосов
/ 01 ноября 2018

data.table решение. dat[, .N, Level] дает количество строк для каждой группы Levels, тогда min(N), т.е. minN - это наименьшее количество строк. Следующая строка занимает верхние minN строки из каждой группы.

library(data.table)
setDT(dat)

minN <- dat[, .N, Level][, min(N)]
dat[, head(.SD, minN), Level]

#     Level          x
#  1:     A  1.2724293
#  2:     A  0.4146414
#  3:     B -0.9285670
#  4:     B -0.2947204
#  5:     C  2.4046534
#  6:     C  0.7635935
#  7:     D -0.2894616
#  8:     D -0.2992151
#  9:     E  0.4356833
# 10:     E -1.2375384

Если вы хотите выбрать случайные строки, вы можете смешать dplyr и data.table

library(dplyr) 

dat[, sample_n(.SD, minN), Level]

Или используйте решение в комментарии arg0naut

dat[, .SD[sample(.N, minN)], by = Level]

Если вы готовы пожертвовать некоторой читабельностью ради скорости, другой вариант -

dat[dat[, sample(.I, minN), Level]$V1]

Использованные данные (из ответа Руи Баррадаса)

set.seed(1)
s <- sample(2:5, 5, TRUE)
Level <- sapply(1:5, function(i) rep(LETTERS[i], each = s[i]))
Level <- factor(unlist(Level))
dat <- data.frame(x = rnorm(length(Level)), Level)
0 голосов
/ 01 ноября 2018

В следующем решении используется только база R.

n <- min(tapply(Level, Level, length))
inx <- unlist(tapply(seq_along(Level), Level, FUN = function(x) sample(x, n)))
dat[inx, ]
#              x Level
#2   0.414641434     A
#3  -1.539950042     A
#5  -0.294720447     B
#6  -0.005767173     B
#9  -0.799009249     C
#8   0.763593461     C
#14  0.252223448     D
#11 -0.289461574     D
#16  0.435683299     E
#17 -1.237538422     E

Я оставил имена строк такими, чтобы было ясно, что они не были выбраны последовательно. Если позже вам понадобятся последовательные имена строк, выполните

sel <- dat[inx, ]
row.names(sel) <- NULL

Данные.

set.seed(1)
s <- sample(2:5, 5, TRUE)
Level <- sapply(1:5, function(i) rep(LETTERS[i], each = s[i]))
Level <- factor(unlist(Level))
dat <- data.frame(x = rnorm(length(Level)), Level)
0 голосов
/ 01 ноября 2018

A dplyr подход с sample_frac для рандомизации:

library(dplyr)

df %>%
  add_count(Level) %>%
  mutate(
    n = min(n)
  ) %>%
  group_by(Level) %>%
  sample_frac(1) %>%
  slice(1:n) %>%
  select(-n)
0 голосов
/ 01 ноября 2018

вот решение dplyr:

library(dplyr)
df %>% group_by(Level) %>%  ## group by level
  mutate(count = n()) %>% ## count number of rows for each group
  ungroup() %>%          
  mutate(count = min(count)) %>%  ## select the minimal number of rows 
  group_by(Level) %>%             ## group again to get X rows for each group
  slice(sample(1:n(), min(count))) %>%    ## get the  X random rows
  ungroup() %>% 
  select(-count)             ## remove the added count variable
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...