Como parametrizar as chamadas de function no dplyr 0.7?

O lançamento do dplyr 0.7 inclui uma grande revisão da programação com o dplyr. Eu li este documento cuidadosamente, e estou tentando entender como isso afetará meu uso do dplyr.

Aqui está um idioma comum que eu uso ao criar relatórios e funções de agregação com dplyr:

my_report % group_by_(.dots=grouping_vars) %>% summarize(x_mean=mean(x), x_median=median(x), ...) } 

Aqui, grouping_vars é um vetor de strings.

Eu gosto deste idioma porque posso passar vetores de strings de outros lugares, digamos um arquivo ou uma interface de usuário reativa do aplicativo Shiny, mas também não é muito ruim para trabalhos interativos.

No entanto, na nova programação com o dplyr vignette , não vejo exemplos de como algo assim pode ser feito com o novo dplyr. Eu só vejo exemplos de como passar seqüências de caracteres não é mais a abordagem correta, e eu tenho que usar quosures em vez disso.

Fico feliz em adotar quasures, mas como exatamente eu recebo de strings para as quosures esperadas por dplyr aqui? Não parece viável esperar que todo o ecossistema R forneça quosures para dplyr – muitas vezes vamos obter strings e elas terão que ser convertidas.

Aqui está um exemplo mostrando o que você deve fazer agora e como meu idioma antigo não 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 terá um group_by group_by_at especializado para lidar com múltiplas variables ​​de agrupamento. Seria muito mais fácil usar o novo membro da família:

 # 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 

O argumento .vars aceita os nomes de vetor / coluna de caractere / numérico gerados por vars :

.vars

Uma lista de colunas geradas por vars (), ou um vetor de caracteres de nomes de colunas, ou um vetor numérico de posições de colunas.

Aqui está a referência rápida e suja que escrevi para mim.

 # 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 nomes de colunas com strings

Converter seqüências de caracteres para objects de símbolo usando rlang::sym e 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 

Se você usar !! ou !!! fora das funções do dplyr você receberá um erro.

O uso de rlang::sym e rlang::syms é idêntico dentro de funções.

 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)) } 

Podemos então chamar summarize_by com argumentos de string.

 summarize_by(dat, "value", c("cat", "cat2")) 

Usando avaliação não padrão para nomes de colunas / 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 

As funções enquo usam enquo vez de quo . quos está bem embora!

 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)) } 

E então a nossa chamada de function é

 summarize_by(dat, value, cat, cat2) 

Se você deseja agrupar por possivelmente mais de uma coluna, você pode usar

 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 

No momento, não parece que há uma ótima maneira de transformar strings em quos. Aqui está uma maneira que funciona embora

 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