r dplyr rlang

¿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.