Условный выбор столбца для фильтрации в R

#r #dplyr

#r #dplyr

Вопрос:

Мои данные имеют такую базовую форму:

 ID <- c(1:9)
Treatment <- c(rep("A", 3), rep("B", 3), rep("C", 3))
v1 <- c(38, 44, 43, rep(NA, 3), 29, 49, 71)
v2 <- c(rep(NA, 3), 59, 32, 50, 73, 69, 34)

df <- tibble(ID, Treatment, v1, v2)
df

     ID Treatment    v1    v2
  <int> <chr>     <dbl> <dbl>
1     1 A            38    NA
2     2 A            44    NA
3     3 A            43    NA
4     4 B            NA    59
5     5 B            NA    32
6     6 B            NA    50
7     7 C            29    73
8     8 C            49    69
9     9 C            71    34
  

Я хочу отфильтровать его таким образом, чтобы сохранялась максимальная строка для v2 в каждой обработке. Однако, если v2 равно NA, то я хочу выбрать максимальное значение v1 для каждой обработки. Мой желаемый результат будет выглядеть так:

 desired_ID desired_Treatment desired_v1 desired_v2
     <dbl> <chr>                  <dbl>      <dbl>
1        2 A                         44         NA
2        4 B                         NA         59
3        7 C                         29         73
  

Я пытаюсь использовать filter in dplyr для этого, но этот код…

 attempt <- df %>%
  group_by(Treatment) %>%
  filter(v1 == max(v1, na.rm = TRUE) | v2 == max(v2, na.rm = TRUE))
  

… приводит к сохранению двух строк из обработки C (максимальное значение для v1 в строке 9 и максимальное значение для v2 в строке 7), чего я не хочу. Кто-нибудь может помочь?

Ответ №1:

Вы можете использовать if/else конструкцию внутри filter , например:

 library(dplyr)

df %>%
  group_by(Treatment) %>%
  filter(if (all(is.na(v2))) v1 == max(v1) else v2 == max(v2))
  

Вывод:

 # A tibble: 3 x 4
# Groups:   Treatment [3]
     ID Treatment    v1    v2
  <int> <chr>     <dbl> <dbl>
1     2 A            44    NA
2     4 B            NA    59
3     7 C            29    73
  

В качестве альтернативы также можно использовать slice with which.max :

 df %>%
  group_by(Treatment) %>%
  slice(if (all(is.na(v2))) which.max(v1) else which.max(v2))