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?
3 Réponses :
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.
Et fonctionnera également avec df%>% mutate (!! col: = tolower (!! sym (col)))
dans la fonction foo
.
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)
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)
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.