avaliação padrão em dplyr: resume na variável dada como uma cadeia de caracteres

Quero me referir a um nome de coluna desconhecido dentro de um summarise . As funções de avaliação padrão introduzidas no dplyr 0.3 permitem que os nomes das colunas sejam referenciados usando variables, mas isso não parece funcionar quando você chama uma function R base dentro de, por exemplo, um summarise .

 library(dplyr) key <- "v3" val <- "v2" drp <- "v1" df <- data_frame(v1 = 1:5, v2 = 6:10, v3 = c(rep("A", 3), rep("B", 2))) 

O df se parece com isso:

 > df Source: local data frame [5 x 3] v1 v2 v3 1 1 6 A 2 2 7 A 3 3 8 A 4 4 9 B 5 5 10 B 

Eu quero largar v1, group por v3 e sum v2 para cada grupo:

 df %>% select(-matches(drp)) %>% group_by_(key) %>% summarise_(sum(val, na.rm = TRUE)) Error in sum(val, na.rm = TRUE) : invalid 'type' (character) of argument 

A versão NSE do select() funciona bem, pois pode corresponder a uma cadeia de caracteres. A versão SE do group_by() funciona bem, já que agora pode aceitar variables ​​como argumentos e avaliá-las. No entanto, não encontrei uma maneira de obter resultados semelhantes ao usar funções R básicas dentro dplyr funções dplyr .

Coisas que não funcionam:

 df %>% group_by_(key) %>% summarise_(sum(get(val), na.rm = TRUE)) Error in get(val) : object 'v2' not found df %>% group_by_(key) %>% summarise_(sum(eval(as.symbol(val)), na.rm = TRUE)) Error in eval(expr, envir, enclos) : object 'v2' not found 

Eu verifiquei várias questões relacionadas , mas nenhuma das soluções propostas funcionou para mim até agora.

Com o lançamento do pacote rlang e a atualização 0.7.0 para dplyr, isso agora é bastante simples.

Quando você quiser usar uma string de caracteres (por exemplo, “v1”) como um nome de variável, você apenas:

  1. Converter a string para um símbolo usando sym() do pacote rlang
  2. Na sua chamada de function, escreva !! na frente do símbolo

Por exemplo, você faria o seguinte:

 my_var < - "Sepal.Length" my_sym <- sym(my_var) summarize(iris, Mean = mean(!!my_sym)) 

De forma mais compacta, você pode combinar a etapa de converter sua string para um símbolo com sym() e prefixá-la com !! ao escrever sua chamada de function.

Por exemplo, você poderia escrever:

 my_var < - "Sepal.Length" summarize(iris, mean(!!sym(my_var))) 

Para retornar ao seu exemplo original, você pode fazer o seguinte:

 library(rlang) key < - "v3" val <- "v2" drp <- "v1" df <- data_frame(v1 = 1:5, v2 = 6:10, v3 = c(rep("A", 3), rep("B", 2))) df %>% # NOTE: we don't have to do anything to `drp` # since the matches() function expects a character string select(-matches(drp)) %>% group_by(!!sym(key)) %>% summarise(sum(!!sym(val), na.rm = TRUE)) 

Detalhes adicionais

De toda a documentação oficial explicando como o uso de sym() e !! funciona, estes parecem ser os mais acessíveis:

  1. vignette dplyr: Programação com dplyr

  2. A seção do livro de Hadley Wickham 'Advanced R' sobre metaprogramação

Por favor note que esta resposta não se aplica a dplyr >= 0.7.0 , mas a versões anteriores.

[ dplyr 0.7.0 ] tem uma nova abordagem para avaliação não padronizada (NSE) chamada de tidyeval. É descrito em detalhe na vignette("programming") .


A vinheta dplyr sobre avaliação não-padrão é útil aqui. Verifique a seção “Misturando constantes e variables” e você lazyeval que a function interp do pacote lazyeval pode ser usada, e “[u] se as.name se você tem uma string de caracteres que dá um nome de variável”:

 library(lazyeval) df %>% select(-matches(drp)) %>% group_by_(key) %>% summarise_(sum_val = interp(~sum(var, na.rm = TRUE), var = as.name(val))) # v3 sum_val # 1 A 21 # 2 B 19 

Passe o argumento .dots uma lista de strings construindo as strings usando paste , sprintf ou usando interpolação de strings do pacote gsubfn via fn$list no lugar de list como fazemos aqui:

 library(gsubfn) df %>% group_by_(key) %>% summarise_(.dots = fn$list(mean = "mean($val)", sd = "sd($val)")) 

dando:

 Source: local data frame [2 x 3] v3 mean sd 1 A 7.0 1.0000000 2 B 9.5 0.7071068 

Nova atualização do dplyr:

A nova funcionalidade do dplyr pode ajudar nisso. Em vez de strings para as variables ​​que precisam de uma avaliação não padrão, usamos quosures quo() . Nós desfazemos as citações com outra function !! . Para mais sobre isso, veja esta vinheta . Você precisará da versão do desenvolvedor do dplyr até o lançamento completo.

 library(dplyr) #0.5.0.9004+ key < - quo(v3) val <- quo(v2) drp <- "v1" df <- data_frame(v1 = 1:5, v2 = 6:10, v3 = c(rep("A", 3), rep("B", 2))) df %>% select(-matches("v1")) %>% group_by(!!key) %>% summarise(sum(!!val, na.rm = TRUE)) # # A tibble: 2 × 2 # v3 `sum(v2, na.rm = TRUE)` #   # 1 A 21 # 2 B 19