¿Cómo parametrizar llamadas de función en dplyr 0.7?
rlang (3)
El lanzamiento de dplyr 0.7 incluye una revisión importante de la programación con dplyr. Leí este documento detenidamente e intento entender cómo afectará mi uso de dplyr.
Aquí hay un idioma común que uso cuando construyo informes y funciones de agregación con dplyr:
my_report <- function(data, grouping_vars) {
data %>%
group_by_(.dots=grouping_vars) %>%
summarize(x_mean=mean(x), x_median=median(x), ...)
}
Aquí,
grouping_vars
es un vector de cadenas.
Me gusta este modismo porque puedo pasar vectores de cadena desde otros lugares, digamos un archivo o la IU reactiva de una aplicación Shiny, pero tampoco es tan malo para el trabajo interactivo.
Sin embargo, en la nueva programación con la viñeta dplyr , no veo ejemplos de cómo se puede hacer algo así con la nueva dplyr. Solo veo ejemplos de cómo pasar cadenas ya no es el enfoque correcto, y en su lugar tengo que usar quosures.
Estoy feliz de adoptar quosures, pero ¿cómo puedo exactamente pasar de cadenas a los quosures que espera dplyr aquí? No parece factible esperar que todo el ecosistema R proporcione quosures a dplyr; muchas veces vamos a obtener cadenas y tendrán que ser convertidos.
Aquí hay un ejemplo que muestra lo que se supone que debes hacer ahora y cómo mi viejo idioma no funciona:
library(dplyr)
grouping_vars <- quo(am)
mtcars %>%
group_by(!!grouping_vars) %>%
summarise(mean_cyl=mean(cyl))
#> # A tibble: 2 × 2
#> am mean_cyl
#> <dbl> <dbl>
#> 1 0 6.947368
#> 2 1 5.076923
grouping_vars <- "am"
mtcars %>%
group_by(!!grouping_vars) %>%
summarise(mean_cyl=mean(cyl))
#> # A tibble: 1 × 2
#> `"am"` mean_cyl
#> <chr> <dbl>
#> 1 am 6.1875
Aquí está la referencia rápida y sucia que escribí para mí.
# install.packages("rlang")
library(tidyverse)
dat <- data.frame(cat = sample(LETTERS[1:2], 50, replace = TRUE),
cat2 = sample(LETTERS[3:4], 50, replace = TRUE),
value = rnorm(50))
Representando nombres de columna con cadenas
Convierta cadenas en objetos de símbolos usando
rlang::sym
y
rlang::syms
.
summ_var <- "value"
group_vars <- c("cat", "cat2")
summ_sym <- rlang::sym(summ_var) # capture a single symbol
group_syms <- rlang::syms(group_vars) # creates list of symbols
dat %>%
group_by(!!!group_syms) %>% # splice list of symbols into a function call
summarize(summ = sum(!!summ_sym)) # slice single symbol into call
Si lo usas
!!
o
!!!
fuera de
dplyr
funciones de
dplyr
obtendrá un error.
El uso de
rlang::sym
y
rlang::syms
es idéntico dentro de las funciones.
summarize_by <- function(df, summ_var, group_vars) {
summ_sym <- rlang::sym(summ_var)
group_syms <- rlang::syms(group_vars)
df %>%
group_by(!!!group_syms) %>%
summarize(summ = sum(!!summ_sym))
}
Entonces podemos llamar a
summarize_by
con argumentos de cadena.
summarize_by(dat, "value", c("cat", "cat2"))
Uso de evaluación no estándar para nombres de columna / variable
summ_quo <- quo(value) # capture a single variable for NSE
group_quos <- quos(cat, cat2) # capture list of variables for NSE
dat %>%
group_by(!!!group_quos) %>% # use !!! with both quos and rlang::syms
summarize(summ = sum(!!summ_quo)) # use !! both quo and rlang::sym
Las funciones
enquo
usan
enquo
lugar de
quo
.
quos
está bien?
summarize_by <- function(df, summ_var, ...) {
summ_quo <- enquo(summ_var) # can only capture a single value!
group_quos <- quos(...) # captures multiple values, also inside functions!?
df %>%
group_by(!!!group_quos) %>%
summarize(summ = sum(!!summ_quo))
}
Y entonces nuestra llamada a la función es
summarize_by(dat, value, cat, cat2)
Si desea agrupar posiblemente más de una columna, puede usar
quos
grouping_vars <- quos(am, gear)
mtcars %>%
group_by(!!!grouping_vars) %>%
summarise(mean_cyl=mean(cyl))
# am gear mean_cyl
# <dbl> <dbl> <dbl>
# 1 0 3 7.466667
# 2 0 4 5.000000
# 3 1 4 4.500000
# 4 1 5 6.000000
En este momento, no parece que haya una excelente manera de convertir las cadenas en quos. Aquí hay una manera que funciona
cols <- c("am","gear")
grouping_vars <- rlang::parse_quosures(paste(cols, collapse=";"))
mtcars %>%
group_by(!!!grouping_vars) %>%
summarise(mean_cyl=mean(cyl))
# am gear mean_cyl
# <dbl> <dbl> <dbl>
# 1 0 3 7.466667
# 2 0 4 5.000000
# 3 1 4 4.500000
# 4 1 5 6.000000
dplyr
tendrá una función especializada group_by
group_by_at
para manejar múltiples variables de agrupación.
Sería mucho más fácil usar el nuevo miembro de la familia
_at
:
# using the pre-release 0.6.0
cols <- c("am","gear")
mtcars %>%
group_by_at(.vars = cols) %>%
summarise(mean_cyl=mean(cyl))
# Source: local data frame [4 x 3]
# Groups: am [?]
#
# am gear mean_cyl
# <dbl> <dbl> <dbl>
# 1 0 3 7.466667
# 2 0 4 5.000000
# 3 1 4 4.500000
# 4 1 5 6.000000
El argumento
.vars
acepta vectores de caracteres / numéricos o nombres de columnas generados por
vars
:
.vars
Una lista de columnas generadas por vars (), o un vector de caracteres de nombres de columna, o un vector numérico de posiciones de columna.