web-dev-qa-db-fra.com

Passer un vecteur de noms de variables pour organiser () dans dplyr

Je veux passer arrange() {dplyr} un vecteur de noms de variables à trier. Habituellement, je tape simplement les variables que je veux, mais j'essaie de créer une fonction où les variables de tri peuvent être entrées en tant que paramètre de fonction.

df <- structure(list(var1 = c(1L, 2L, 2L, 3L, 1L, 1L, 3L, 2L, 4L, 4L
  ), var2 = structure(c(10L, 1L, 8L, 3L, 5L, 4L, 7L, 9L, 2L, 6L
  ), .Label = c("b", "c", "f", "h", "i", "o", "s", "t", "w", "x"
  ), class = "factor"), var3 = c(7L, 5L, 5L, 8L, 5L, 8L, 6L, 7L, 
  5L, 8L), var4 = structure(c(8L, 5L, 1L, 4L, 7L, 4L, 3L, 6L, 9L, 
  2L), .Label = c("b", "c", "d", "e", "f", "h", "i", "w", "y"), 
  class = "factor")), .Names = c("var1", "var2", "var3", "var4"), 
  row.names = c(NA, -10L), class = "data.frame")

# this is the normal way to arrange df with dplyr
df %>% arrange(var3, var4)

# but none of these (below) work for passing a vector of variables
vector_of_vars <- c("var3", "var4")
df %>% arrange(vector_of_vars)
df %>% arrange(get(vector_of_vars))
df %>% arrange(eval(parse(text = paste(vector_of_vars, collapse = ", "))))
35
rsoren

Hadley n'a pas rendu cela évident dans le fichier d'aide - seulement dans sa vignette NSE. Les versions des fonctions suivies de soulignements utilisent une évaluation standard, vous leur transmettez donc des vecteurs de chaînes, etc.

Si je comprends bien votre problème, vous pouvez simplement remplacer arrange() par arrange_() et cela fonctionnera.

Spécifiquement, passez le vecteur de chaînes comme argument .dots Lorsque vous le faites.

> df %>% arrange_(.dots=c("var1","var3"))
   var1 var2 var3 var4
1     1    i    5    i
2     1    x    7    w
3     1    h    8    e
4     2    b    5    f
5     2    t    5    b
6     2    w    7    h
7     3    s    6    d
8     3    f    8    e
9     4    c    5    y
10    4    o    8    c

========== Mise à jour de mars 2018 ==============

L'utilisation des versions d'évaluation standard dans dplyr comme je l'ai montré ici est maintenant considérée comme obsolète . Vous pouvez lire vignette de programmation de Hadley pour la nouvelle façon. Fondamentalement, vous utiliserez !! Pour supprimer une variable ou !!! Pour supprimer un vecteur de variables à l'intérieur de arrange().

Lorsque vous passez ces colonnes, si elles sont nues, citez-les en utilisant quo() pour une variable ou quos() pour un vecteur. N'utilisez pas de guillemets. Voir la réponse d'Akrun.

Si vos colonnes sont déjà des chaînes, faites-leur des noms en utilisant rlang::sym() pour une seule colonne ou rlang::syms() pour un vecteur. Voir la réponse de Christos. Vous pouvez également utiliser as.name() pour une seule colonne. Malheureusement, au moment de la rédaction de ce document, les informations sur la façon d'utiliser rlang::sym() ne sont pas encore entrées dans la vignette à laquelle je renvoie ci-dessus (elles figureront finalement dans la section sur la "quasiquotation variadique" selon son projet).

33
farnsy

Dans la nouvelle version (bientôt disponible 0.6.0 de dplyr) nous pouvons utiliser le quosures

library(dplyr)
vector_of_vars <- quos(var1, var3)
df %>%
    arrange(!!! vector_of_vars)
#   var1 var2 var3 var4
#1     1    i    5    i
#2     1    x    7    w
#3     1    h    8    e
#4     2    b    5    f
#5     2    t    5    b
#6     2    w    7    h
#7     3    s    6    d
#8     3    f    8    e
#9     4    c    5    y
#10    4    o    8    c

Lorsqu'il y a plus d'une variable, nous utilisons quos et pour une seule variable c'est quo. Le quos renverra un list des variables entre guillemets et à l'intérieur du arrange, nous citerons le list en utilisant !!! pour évaluation

17
akrun

Dans l'esprit des quosures:

df %>% arrange(!!! rlang::syms(c("var1", "var3")))

Pour une variable unique, cela ressemblerait à:

df %>% arrange(!! rlang::sym(c("var1")))
15
Christos

Je pense que maintenant vous pouvez simplement utiliser dplyr::arrange_at().

library(dplyr)

### original
head(iris)
#   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
# 1          5.1         3.5          1.4         0.2  setosa
# 2          4.9         3.0          1.4         0.2  setosa
# 3          4.7         3.2          1.3         0.2  setosa
# 4          4.6         3.1          1.5         0.2  setosa
# 5          5.0         3.6          1.4         0.2  setosa
# 6          5.4         3.9          1.7         0.4  setosa

### arranged
iris %>% 
  arrange_at(c("Sepal.Length", "Sepal.Width")) %>% 
  head()
#   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
# 1          4.3         3.0          1.1         0.1  setosa
# 2          4.4         2.9          1.4         0.2  setosa
# 3          4.4         3.0          1.3         0.2  setosa
# 4          4.4         3.2          1.3         0.2  setosa
# 5          4.5         2.3          1.3         0.3  setosa
# 6          4.6         3.1          1.5         0.2  setosa
5
Cecilia Lee

Essaye ça:

df %>% do(do.call(arrange_, . %>% list(.dots = vector_of_vars)))

et en fait cela peut être écrit plus simplement comme:

df %>% arrange_(.dots = vector_of_vars)

bien qu'à ce stade, je pense que c'est la même chose que la solution implicite de farnsy.

3
G. Grothendieck