Je veux faire référence à un nom de colonne inconnu dans un summarise
. Les fonctions d'évaluation standard introduites dans dplyr 0.3
Permettent de référencer les noms de colonnes à l'aide de variables, mais cela ne semble pas fonctionner lorsque vous appelez une fonction base
R dans par exemple un 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)))
Le df ressemble à ceci:
> 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
Je veux supprimer v1, grouper par v3 et additionner v2 pour chaque groupe:
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
La version NSE de select()
fonctionne très bien, car elle peut correspondre à une chaîne de caractères. La version SE de group_by()
fonctionne très bien, car elle peut désormais accepter des variables comme arguments et les évaluer. Cependant, je n'ai pas trouvé de moyen d'obtenir des résultats similaires lors de l'utilisation des fonctions de base R dans les fonctions dplyr
.
Choses qui ne fonctionnent pas:
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
J'ai vérifié plusieursliésquestions , mais aucune des solutions proposées n'a fonctionné pour moi jusqu'à présent.
Avec la sortie du paquet rlang et la mise à jour 0.7.0 de dplyr, c'est maintenant assez simple.
Lorsque vous souhaitez utiliser une chaîne de caractères (par exemple, "v1") comme nom de variable, vous n'avez qu'à:
sym()
à partir du package rlang!!
Devant le symbolePar exemple, vous feriez ce qui suit:
my_var <- "Sepal.Length"
my_sym <- sym(my_var)
summarize(iris, Mean = mean(!!my_sym))
De manière plus compacte, vous pouvez combiner l'étape de conversion de votre chaîne en symbole avec sym()
et en la préfixant avec !!
Lors de l'écriture de votre appel de fonction.
Par exemple, vous pourriez écrire:
my_var <- "Sepal.Length"
summarize(iris, mean(!!sym(my_var)))
Pour revenir à votre exemple d'origine, vous pouvez procéder comme suit:
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))
Syntaxe alternative
Avec la version de rlang version 0.4.0, vous pouvez utiliser la syntaxe suivante:
my_var <- "Sepal.Length"
my_sym <- sym(my_var)
summarize(iris, Mean = mean({{ my_sym }}))
Au lieu d'écrire !!my_sym
, Vous pouvez écrire {{ my_sym }}
. Cela a l'avantage d'être sans doute plus clair, mais a l'inconvénient que vous devez convertir la chaîne en symbole avant de la placer à l'intérieur des crochets. Par exemple, vous pouvez écrire !!sym(my_var)
mais vous ne peut pas écrire {{sym(my_var)}}
Détails supplémentaires
De toute la documentation officielle expliquant le fonctionnement de sym()
et !!
, Celles-ci semblent être les plus accessibles:
Veuillez noter que cette réponse ne s'applique pas à dplyr >= 0.7.0
, Mais aux versions précédentes.
[
dplyr 0.7.0
] a une nouvelle approche de l'évaluation non standard (NSE) appelée tidyeval. Il est décrit en détail dansvignette("programming")
.
La vignette dplyr
sur l'évaluation non standard est utile ici. Vérifiez la section "Mélange de constantes et de variables" et vous constaterez que la fonction interp
du package lazyeval
pourrait être utilisée, et "[u] se as.name
Si vous avez un caractère chaîne qui donne un nom de variable ":
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 le .dots
argument une liste de chaînes construisant les chaînes en utilisant paste
, sprintf
ou en utilisant l'interpolation de chaînes du package gsubfn via fn$list
à la place de list
comme nous le faisons ici:
library(gsubfn)
df %>%
group_by_(key) %>%
summarise_(.dots = fn$list(mean = "mean($val)", sd = "sd($val)"))
donnant:
Source: local data frame [2 x 3]
v3 mean sd
1 A 7.0 1.0000000
2 B 9.5 0.7071068
Nouvelle mise à jour de dplyr:
La nouvelle fonctionnalité de dplyr peut vous y aider. Au lieu de chaînes pour les variables qui nécessitent une évaluation non standard, nous utilisons des quosures quo()
. Nous annulons la citation avec une autre fonction !!
. Pour en savoir plus voir cette vignette . Vous aurez besoin de la version développeur de dplyr jusqu'à la version complète.
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)`
# <chr> <int>
# 1 A 21
# 2 B 19