изменение с помощью ifelse (), когда условие требует, чтобы любой член группы ему удовлетворял - PullRequest
1 голос
/ 14 июля 2020

Я хотел бы использовать функции dplyr для создания нового значения на основе другой переменной, если группа содержит переменную, которая соответствует моему условию.

Теперь, поскольку я пытался, но не смог получить указанное выше Чтобы звучать яснее, краткий пример:

library(dplyr)
df <- data.frame(id = c(1,1,1,2,2,2,3,3), var = c(1,2,3,4,5,6,7,8), gender = c("M", "M", "M", "M", "M", "F", "F", "M"), stringsAsFactors = FALSE)

Здесь я хочу создать новую переменную (newvar), где

  1. , если группа (id) содержит любую женщину member ("F"), newvar должно иметь то же значение, что и var
  2. , если группа состоит только из мужчин, newvar должно иметь значение 1

Мой ожидаемый результат:

# id var gender newvar
#  1   1     M       1 
#  1   2     M       1
#  1   3     M       1
#  2   4     M       4
#  2   5     M       5
#  2   6     F       6
#  3   7     F       7
#  3   8     M       8  

Моя попытка:

df %>% 
  group_by(id) %>%
  mutate(newvar = ifelse(any(gender == "F"), var, 1))

Мой результат:

# id var gender newvar
#  1   1     M       1 
#  1   2     M       1
#  1   3     M       1
#  2   4     M       4
#  2   5     M       4
#  2   6     F       4
#  3   7     F       7
#  3   8     M       7  

Это происходит каждый раз, когда я использую group_by и mutate вместе, где функция ifelse имеет условие, которое использует функцию any, и либо результат ИСТИНА, либо ЛОЖЬ прибегает к другому столбцу - так, на словах, когда я говорю коду «создать столбец, значения которого зависят от в группе, где, если какой-либо из членов группы удовлетворяет условию, пусть он имеет значение которые зависят от другого (3-го) столбца, но если ни один из членов не удовлетворяет этому условию, пусть он имеет другое значение '

Я был бы признателен, если бы я мог узнать (1) почему моя попытка не удалась и (2) Какая была бы лучшая / лучшая версия написания кода, которая принесет желаемый результат.

(PS Я знаю заголовок и первый абзац - отстой, но не могу заставить его звучать лучше ..)

Ответы [ 2 ]

4 голосов
/ 14 июля 2020

Как уже объяснил Ян, длина условия test равна единице, следовательно, результат ifelse также имеет длину 1, которая повторяется для всего столбца.

Здесь вы можете использовать if / else вместо ifelse

library(dplyr)
df %>% group_by(id) %>% mutate(newvar = if(any(gender == "F")) var else 1)

#     id   var gender newvar
#  <dbl> <dbl> <chr>   <dbl>
#1     1     1 M           1
#2     1     2 M           1
#3     1     3 M           1
#4     2     4 M           4
#5     2     5 M           5
#6     2     6 F           6
#7     3     7 F           7
#8     3     8 M           8
4 голосов
/ 14 июля 2020

Причина, по которой ваша версия не обеспечивает ожидаемый результат, заключается в том, что any(gender == "F") оценивает длину в один логический вектор. Таким образом, значение для этой группы будет иметь длину один и будет повторяться для заполнения группы.

Вот подход с map_dbl из purrr:

library(purrr)
df %>% 
  group_by(id) %>%
  mutate(newvar = map_dbl(var, ~if_else(any(gender == "F"), .x, 1)))
## A tibble: 8 x 4
## Groups:   id [3]
#     id   var gender newvar
#  <dbl> <dbl> <chr>   <dbl>
#1     1     1 M           1
#2     1     2 M           1
#3     1     3 M           1
#4     2     4 M           4
#5     2     5 M           5
#6     2     6 F           6
#7     3     7 F           7
#8     3     8 M           8

Альтернативный подход - повторить логический вектор, созданный any, чтобы иметь длину var:

df %>% 
  group_by(id) %>%
  mutate(newvar = if_else(rep(any(gender == "F"),n()), var, 1))
# A tibble: 8 x 4
# Groups:   id [3]
#     id   var gender newvar
#  <dbl> <dbl> <chr>   <dbl>
#1     1     1 M           1
#2     1     2 M           1
#3     1     3 M           1
#4     2     4 M           4
#5     2     5 M           5
#6     2     6 F           6
#7     3     7 F           7
#8     3     8 M           8
...