¿Cómo parametrizar llamadas de función en dplyr 0.7?

El lanzamiento de dplyr 0.7 incluye una importante revisión de la progtwigción con dplyr. Leí este documento detenidamente y estoy tratando de comprender cómo afectará mi uso de dplyr.

Aquí hay una expresión común que uso cuando construyo informes y funciones de agregación con dplyr:

my_report % 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 cadenas de otros lugares, por ejemplo, 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 progtwigción con dplyr vignette , no veo ejemplos de cómo hacer algo como esto con el nuevo dplyr. Solo veo ejemplos de cómo pasar cadenas ya no es el enfoque correcto, y tengo que usar quosures en su lugar.

Estoy contento de adoptar quosures, pero ¿cómo puedo obtener exactamente las cadenas que quiso Dplyr? No parece factible esperar que todo el ecosistema R proporcione quosures a dplyr – muchas veces vamos a obtener cadenas y tendrán que convertirse.

Aquí hay un ejemplo que muestra lo que se supone que debes hacer y cómo mi antiguo idioma no funciona:

 library(dplyr) grouping_vars % group_by(!!grouping_vars) %>% summarise(mean_cyl=mean(cyl)) #> # A tibble: 2 × 2 #> am mean_cyl #>   #> 1 0 6.947368 #> 2 1 5.076923 grouping_vars % group_by(!!grouping_vars) %>% summarise(mean_cyl=mean(cyl)) #> # A tibble: 1 × 2 #> `"am"` mean_cyl #>   #> 1 am 6.1875 

dplyr tendrá una función group_by_at para tratar con 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 #    # 1 0 3 7.466667 # 2 0 4 5.000000 # 3 1 4 4.500000 # 4 1 5 6.000000 

El argumento .vars acepta tanto caracteres / vectores numéricos como nombres de columna 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.

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 a 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 usas !! o !!! fuera de dplyr funciones 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")) 

Usar una evaluación no estándar para nombres de columnas / variables

 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 sin embargo !?

 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 luego nuestra llamada de 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 #    # 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 gran manera de convertir cadenas en quos. Aquí hay una manera que funciona aunque

 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 #    # 1 0 3 7.466667 # 2 0 4 5.000000 # 3 1 4 4.500000 # 4 1 5 6.000000