Выберите случайную строку в случае связей в сгруппированном DF - PullRequest
1 голос
/ 21 мая 2019

У меня есть фрейм данных, как показано ниже

df <- data.frame(group_var = c("a", "a", "b", "b"),
           summ_var = c("x", "y", "z", "w"),
           val = c(100, 100, 150, 200))

df
  group_var summ_var val
1         a        x 100
2         a        y 100
3         b        z 150
4         b        w 200

Для каждого group_var я хочу выбрать ровно один summ_var с минимальным val. Я пробовал следующий код:

df %>% 
    group_by(group_var) %>% 
    filter(val == min(val)) %>% 
    ungroup()

  group_var summ_var   val
  <fct>     <fct>    <dbl>
1 a         x          100
2 a         y          100
3 b         z          150

, что дает мне кратное summ_var для group_var = a, поскольку val == min(val) равно TRUE для нескольких значений summ_var. Как случайно выбрать одно из нескольких значений summ_var для group_var = a?

Мой желаемый результат выглядит следующим образом: случайное значение summ_var выбирается в каждой группе в случае конфликта.

  group_var summ_var   val
  <fct>     <fct>    <dbl>
1 a         x          100
2 b         z          150

Это просто воспроизводимый пример, в действительности у меня может быть более двух конфликтующих значений. Поэтому ищем обобщенный подход. Любая помощь приветствуется.

Ответы [ 2 ]

3 голосов
/ 21 мая 2019

С dplyr вы можете сделать:

df %>%
 group_by(group_var) %>%
 slice(which.min(rank(val, ties.method = "random")))

  group_var summ_var   val
  <fct>     <fct>    <dbl>
1 a         x          100
2 b         z          150

Или:

df %>%
 group_by(group_var) %>%
 filter(val == min(val)) %>%
 sample_frac(1) %>%
 slice(1)
0 голосов
/ 21 мая 2019

Мы можем использовать slice с sample из row_number()

library(dplyr)
df %>% 
   group_by(group_var) %>%
   slice(sample(row_number()[val == min(val)], 1))
# A tibble: 2 x 3
# Groups:   group_var [2]
#  group_var summ_var   val
#  <fct>     <fct>    <dbl>
#1 a         x          100
#2 b         z          150

Или используя data.table

library(data.table)
setDT(df)[, .SD[min(frank(val, ties.method = 'random'))], group_var]
#   group_var summ_var val
#1:         a        x 100
#2:         b        z 150
...