web-dev-qa-db-fra.com

case_when dans un tuyau muté

Il semble dplyr::case_when ne se comporte pas comme les autres commandes d'un dplyr::mutate appel. Par exemple:

library(dplyr)

case_when(mtcars$carb <= 2 ~ "low",
          mtcars$carb > 2 ~ "high") %>% 
  table

travaux:

.
high  low 
  15   17 

Mais mettez case_when dans une chaîne mutate:

mtcars %>% 
  mutate(cg = case_when(carb <= 2 ~ "low",
                        carb > 2 ~ "high"))

et vous obtenez:

 Error: object 'carb' not found

alors que cela fonctionne bien

mtcars %>% 
  mutate(cg = carb %>% 
           cut(c(0, 2, 8)))
31
tomw

À partir de la version 0.7.0 de dplyr, case_when fonctionne dans mutate comme suit:

library(dplyr) # >= 0.7.0
mtcars %>% 
  mutate(cg = case_when(carb <= 2 ~ "low",
                        carb > 2  ~ "high"))

Pour plus d'informations: http://dplyr.tidyverse.org/reference/case_when.html

40
George Wood

On peut utiliser .$

mtcars %>%  
     mutate(cg = case_when(.$carb <= 2 ~ "low",  .$carb > 2 ~ "high")) %>%
    .$cg %>%
    table()
# high  low 
#  15   17 
16
akrun

Avec merci à @sumedh: @hadley a expliqué qu'il s'agit d'une lacune connue de case_when:

case_when() est encore un peu expérimental et ne fonctionne pas actuellement dans mutate(). Ce sera corrigé dans une future version.

6
tomw

Dans mon cas, la quasiquotation a beaucoup aidé. Vous pouvez créer à l’avance un ensemble de formules citées définissant les règles de mutation (et utiliser les noms de colonne connus comme dans la première formule ou tirer parti de !! et créer des règles dynamiquement comme dans la deuxième formule), qui est ensuite utilisé dans mutate - case_when combinaison comme ici

    library(dplyr)
    library(rlang)
    pattern <- quos(gear == 3L ~ "three", !!sym("gear") == 4L ~ "four", gear == 5L ~ "five")
    # Or
    # pattern <- list(
    #     quo(gear == 3L ~ "three"), 
    #     quo(!!sym("gear") == 4L ~ "four"),
    #     quo(gear == 5L ~ "five"))
    #
    mtcars %>% mutate(test = case_when(!!!pattern)) %>% head(10L)
#>     mpg cyl  disp  hp drat    wt  qsec vs am gear carb  test
#> 1  21.0   6 160.0 110 3.90 2.620 16.46  0  1    4    4  four
#> 2  21.0   6 160.0 110 3.90 2.875 17.02  0  1    4    4  four
#> 3  22.8   4 108.0  93 3.85 2.320 18.61  1  1    4    1  four
#> 4  21.4   6 258.0 110 3.08 3.215 19.44  1  0    3    1 three
#> 5  18.7   8 360.0 175 3.15 3.440 17.02  0  0    3    2 three
#> 6  18.1   6 225.0 105 2.76 3.460 20.22  1  0    3    1 three
#> 7  14.3   8 360.0 245 3.21 3.570 15.84  0  0    3    4 three
#> 8  24.4   4 146.7  62 3.69 3.190 20.00  1  0    4    2  four
#> 9  22.8   4 140.8  95 3.92 3.150 22.90  1  0    4    2  four
#> 10 19.2   6 167.6 123 3.92 3.440 18.30  1  0    4    4  four

Je préfère une telle solution car elle permet de créer des règles complexes, par exemple. en utilisant map2 avec les conditions LHS et les valeurs RHS pour générer les formules citées

    library(rlang)
    library(purrr)
    map2(c(3, 4, 5), c("three", "four", "five"), ~quo(gear == !!.x ~ !!.y))
#> [[1]]
#> <quosure>
#> expr: ^gear == 3 ~ "three"
#> env:  0000000014286520
#> 
#> [[2]]
#> <quosure>
#> expr: ^gear == 4 ~ "four"
#> env:  000000001273D0E0
#> 
#> [[3]]
#> <quosure>
#> expr: ^gear == 5 ~ "five"
#> env:  00000000125870E0

et l'utiliser à différents endroits, en appliquant différents ensembles de données sans avoir à saisir manuellement toutes les règles chaque fois que vous avez besoin d'une mutation complexe.

En guise de réponse finale au problème, 7 symboles supplémentaires et deux parenthèses le résolvent

library(rlang)
library(dplyr)
mtcars %>% 
    mutate(test = case_when(!!!quos(gear == 3L ~ "three", gear != 3L ~ "not three"))) %>% 
    head(10L)
#>     mpg cyl  disp  hp drat    wt  qsec vs am gear carb      test
#> 1  21.0   6 160.0 110 3.90 2.620 16.46  0  1    4    4 not three
#> 2  21.0   6 160.0 110 3.90 2.875 17.02  0  1    4    4 not three
#> 3  22.8   4 108.0  93 3.85 2.320 18.61  1  1    4    1 not three
#> 4  21.4   6 258.0 110 3.08 3.215 19.44  1  0    3    1     three
#> 5  18.7   8 360.0 175 3.15 3.440 17.02  0  0    3    2     three
#> 6  18.1   6 225.0 105 2.76 3.460 20.22  1  0    3    1     three
#> 7  14.3   8 360.0 245 3.21 3.570 15.84  0  0    3    4     three
#> 8  24.4   4 146.7  62 3.69 3.190 20.00  1  0    4    2 not three
#> 9  22.8   4 140.8  95 3.92 3.150 22.90  1  0    4    2 not three
#> 10 19.2   6 167.6 123 3.92 3.440 18.30  1  0    4    4 not three

Créé le 2019-01-16 par le paquetage reprex (v0.2.1.9000)

3
Ilia