2
votes

comprendre rlang: muter avec le nom de la colonne variable et la colonne variable

Je voudrais définir une fonction qui prend un data.frame et un nom de colonne et renvoie le data.frame avec cette colonne transformée (par exemple en minuscules). Lorsque le nom de la colonne est connu à l'avance, c'est simple:

col <- "cut"
foo(diamonds, col) 

Error in ~col : object 'col' not found

Comment définir une fonction foo , telle que:

foo <- function(df, col){
    col <- ensym(col)
    x <- enquo(col)
    mutate(df, !!x := tolower(!!x))
}

ce comportement est-il le même? (Je ne recherche pas de réponse de base R ou data.table car je veux préserver la capacité de dplyr à traduire cela en un appel SQL évalué paresseusement).

Si je voulais juste que ma fonction fonctionne en utilisant: foo (diamants, coupe) , j'ai juste besoin de enquo et !! code>

foo <- function(df, col){
    x <- enquo(col)
    mutate(df, !!x := tolower(!!x))
}

Si je veux prendre le nom de la colonne entre guillemets, foo (losanges, "cut") , en ajoutant ensym est suffisant:

col <- "cut"
foo(diamonds, col) 

mais cela échoue lorsqu'on lui donne une variable pour un argument:

diamonds %>% mutate(cut = tolower(cut))

Que suis-je manquant qui peut évaluer la variable?


0 commentaires

3 Réponses :


3
votes
library(tidyverse)

col <- "cut"

foo <- function(df, col) {
  df %>% 
    mutate(!!sym(col) := tolower(!!sym(col)))
}

foo(diamonds, col)
Check out Pass a string as variable name in dplyr::filter.

1 commentaires

Et fonctionnera également avec df%>% mutate (!! col: = tolower (!! sym (col))) dans la fonction foo .



7
votes

Vous pouvez également éviter une évaluation ordonnée entièrement ici en utilisant mutate_at().

library(tidyverse)

(x <- tibble(
  num = 1:3,
  month = month.abb[num]
))
#> # A tibble: 3 x 2
#>     num month
#>   <int> <chr>
#> 1     1 Jan  
#> 2     2 Feb  
#> 3     3 Mar

x %>%
  mutate(month = tolower(month))
#> # A tibble: 3 x 2
#>     num month
#>   <int> <chr>
#> 1     1 jan  
#> 2     2 feb  
#> 3     3 mar

foo <- function(df, col) {
  mutate_at(df, .vars = col, .funs = tolower)
}

foo(x, "month")
#> # A tibble: 3 x 2
#>     num month
#>   <int> <chr>
#> 1     1 jan  
#> 2     2 feb  
#> 3     3 mar

this <- "month"
foo(x, this)
#> # A tibble: 3 x 2
#>     num month
#>   <int> <chr>
#> 1     1 jan  
#> 2     2 feb  
#> 3     3 mar

Créé le 2019-03-09 par le paquet reprex (v0.2.1.9000)


0 commentaires

2
votes

Pour revenir à votre exemple d'origine, utilisez simplement ensym () pour convertir les arguments de texte en symboles, il n'y a pas besoin de quosure dans ce cas.

library(ggplot2)
col <- "cut"
foo <- function(df, col){
    col <- rlang::sym(col)
    dplyr::mutate(df, !!col := tolower(!!col))
}

foo(diamonds, col)
#> # A tibble: 53,940 x 10
#>    carat cut       color clarity depth table price     x     y     z
#>    <dbl> <chr>     <ord> <ord>   <dbl> <dbl> <int> <dbl> <dbl> <dbl>
#>  1 0.23  ideal     E     SI2      61.5    55   326  3.95  3.98  2.43
#>  2 0.21  premium   E     SI1      59.8    61   326  3.89  3.84  2.31
#>  3 0.23  good      E     VS1      56.9    65   327  4.05  4.07  2.31
#>  4 0.290 premium   I     VS2      62.4    58   334  4.2   4.23  2.63
#>  5 0.31  good      J     SI2      63.3    58   335  4.34  4.35  2.75
#>  6 0.24  very good J     VVS2     62.8    57   336  3.94  3.96  2.48
#>  7 0.24  very good I     VVS1     62.3    57   336  3.95  3.98  2.47
#>  8 0.26  very good H     SI1      61.9    55   337  4.07  4.11  2.53
#>  9 0.22  fair      E     VS2      65.1    61   337  3.87  3.78  2.49
#> 10 0.23  very good H     VS1      59.4    61   338  4     4.05  2.39
#> # … with 53,930 more rows

Créé le 11/03/2019 par le package reprex (v0.2.1)


2 commentaires

merci, mais dans ce cas, cela ne semble pas donner le comportement souhaité? Me donne une colonne littéralement appelée col ...


Oups, vous avez raison, je l'ai édité pour faire la bonne chose maintenant.