назначить несколько значений с условным изменением - PullRequest
0 голосов
/ 09 мая 2018

Можно ли использовать один условный вызов mutate для присвоения значений нескольким переменным?

Например, в приведенном ниже примере, когда cat == "a", я хочу присвоить значение «1» для столбца «foo», а также значение «три» для столбца «bar». Аналогично, когда cat == "b", присвойте «2» и «четыре».

Следующее достигается этим, но требует, чтобы вызов case_when повторялся для каждой переменной

require(tidyverse)
df <- tibble(cat = c("a", "b", "a", "a", "c"))
df %>%
  mutate(foo = case_when(cat == "a" ~ 1,
                         cat == "b" ~ 2,
                         TRUE ~ NA_real_)) %>%
  mutate(bar = case_when(cat == "a" ~ "three",
                         cat == "b" ~ "four",
                         TRUE ~ NA_character_))

Я думал, что создание столбца списка может быть полезным, что-то вроде

df %>%
  mutate(case_when(cat == "a" ~ list("foo" = 1, "bar" = "three"),
                   cat == "b" ~ list("foo" = 2, "bar" = "four"),
                   TRUE ~ NA_real_))

, но case_when принимает только отдельные значения для RHS.

Одним из решений (например, здесь ) является создание «эталонного» фрейма данных и join его, например

require(tidyverse)    
ref <- tibble(cat = c("a", "b"), foo = c(1, 2), bar = c("three", "four"))
df %>% left_join(ref)

однако это не будет работать, когда «условие» не является категориальным, например, x > 2

Есть предложения по хорошему способу сделать это? Спасибо

Ответы [ 3 ]

0 голосов
/ 09 мая 2018

То, что вы описываете, довольно близко к функциональности data.table, где вы можете предоставить список столбцов и значений для обновления (по ссылке, т.е. без копирования) на основе определенного условия:

library(data.table)
dt <- as.data.table(df) # or use setDT(df)
dt[cat == "a", `:=`(foo = 1, bar = "three")]
dt[cat == "b", `:=`(foo = 2, bar = "four")]
0 голосов
/ 09 мая 2018

Зависит от того, насколько масштабируемым должно быть все это. Может стоит посмотреть:

require(tidyverse)
df <- tibble(cat = c("a", "b", "a", "a", "c"))

# create single case_when
make_fun <- function(values) {
  trans_fun <- function(x) {
    case_when(x == "a" ~ values[[1]],
              x == "b" ~ values[[2]],
              TRUE ~ values[[3]])
  }
}

# create all case_whens
fun_list <- list(
  foo = make_fun(list(1, 2, NA_real_)),
  bar = make_fun(list("three", "four", NA_character_)))

# join is not really necessary
df %>%
  bind_cols(map(fun_list, 
                function(f) f(df %>%
                                select(cat))))
0 голосов
/ 09 мая 2018

Я предлагаю метод join, но с промежуточным столбцом:

library(dplyr)
df <- data_frame(cat = c(1L, 2L, 3L, 4L))
otherdf <- data_frame(j=c('a1','a2','a99'), foo=11:13, bar=c('three','four','five'))

df %>%
  mutate(
    j = case_when(
      cat == 1L ~ 'a1',
      cat == 2L ~ 'a2',
      cat > 2L ~ 'a99'
    )) %>%
  left_join(otherdf, by = 'j')
# # A tibble: 4 × 4
#     cat     j   foo   bar
#   <int> <chr> <int> <chr>
# 1     1    a1    11 three
# 2     2    a2    12  four
# 3     3   a99    13  five
# 4     4   a99    13  five

(Тогда вы, очевидно, можете очистить его с помощью select(-j).)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...