J'essaie de transférer ma compréhension de plyr dans dplyr, mais je ne peux pas comprendre comment grouper par plusieurs colonnes.
# make data with weird column names that can't be hard coded
data = data.frame(
asihckhdoydkhxiydfgfTgdsx = sample(LETTERS[1:3], 100, replace=TRUE),
a30mvxigxkghc5cdsvxvyv0ja = sample(LETTERS[1:3], 100, replace=TRUE),
value = rnorm(100)
)
# get the columns we want to average within
columns = names(data)[-3]
# plyr - works
ddply(data, columns, summarize, value=mean(value))
# dplyr - raises error
data %.%
group_by(columns) %.%
summarise(Value = mean(value))
#> Error in eval(expr, envir, enclos) : index out of bounds
Que me manque-t-il pour traduire l'exemple plyr en une syntaxe dplyr-esque?
Edit 2017 : Dplyr a été mis à jour, donc une solution plus simple est disponible. Voir la réponse actuellement sélectionnée.
group_by_
maintenant expliqué dansvignette("nse")
.dots
. Voici la solution adaptée de la réponse de @hadley ci-dessous:df %>% group_by_(.dots=list(quote(asihckhdoydk), quote(a30mvxigxkgh))) %>% summarise(n = n())
Réponses:
Depuis que cette question a été publiée, dplyr a ajouté des versions étendues de
group_by
( documentation ici ). Cela vous permet d'utiliser les mêmes fonctions que vous utiliseriez avecselect
, comme ceci:La sortie de votre exemple de question est comme prévu (voir la comparaison avec plyr ci-dessus et la sortie ci-dessous):
Notez que comme
dplyr::summarize
ne supprime qu'une couche de regroupement à la fois, vous avez toujours du regroupement en cours dans le tibble résultant (qui peut parfois surprendre les gens plus tard sur la ligne). Si vous voulez être absolument à l'abri d'un comportement de regroupement inattendu, vous pouvez toujours ajouter%>% ungroup
à votre pipeline après avoir résumé.la source
0.7.0
rendre le système quote-unquote disponible avec plusieurs colonnes également?.dots
arguments engroup_by()
tant que tel:data %>% group_by(.dots = columns) %>% summarize(value = mean(value))
.one_of()
faire quelque chose ici? Je pense que c'est redondant dans ce contexte, car l'expression est enveloppée dans un appel àvars()
.one_of()
est redondant dans ce contexteselect
syntaxe, voir la nouvelleacross
fonction: dplyr.tidyverse.org/reference/across.html Dans votre cas, cela ressemblerait à quelque chose commesummarize(across(all_of(c(''value_A", "value_B")), mean))
Juste pour écrire le code dans son intégralité, voici une mise à jour de la réponse de Hadley avec la nouvelle syntaxe:
production:
la source
asihckhdoydk
...dots <- lapply(names(df)[-3], function(x) as.symbol(x))
pour créer l'.dots
argument.dots=
était l'étape cruciale. si quelqu'un a une bonne idée de la raison pour laquelle cela est requis dans l'group_by
appel, pouvez-vous modifier cette réponse? en ce moment, c'est un peu impénétrable.vignette("nse")
indique qu'il existe trois façons de citer qui sont acceptables: formule, citation et caractère. À moins que vous ne vous inquiétiez de l'environnement dont il tirera, vous pourrez probablement vous en sortirgroup_by_(.dots=grp_cols)
Le support pour cela dans dplyr est actuellement assez faible, finalement je pense que la syntaxe sera quelque chose comme:
Mais cela ne sera probablement pas là avant un certain temps (car j'ai besoin de réfléchir à toutes les conséquences).
En attendant, vous pouvez utiliser
regroup()
, qui prend une liste de symboles:Si vous avez un vecteur de caractères de noms de colonnes, vous pouvez les convertir dans la bonne structure avec
lapply()
etas.symbol()
:la source
as.symbol
le résout. Merci! Au cas où cela aiderait au développement: ce scénario est très courant pour moi. Agréger un résultat numérique sur chaque combinaison des autres variables.regroup
est également obsolète (au moins à partir de la version 0.4.3).La spécification de chaîne de colonnes dans
dplyr
est désormais prise en charge via des variantes desdplyr
fonctions dont les noms se terminent par un trait de soulignement. Par exemple, correspondant à lagroup_by
fonction, il existe unegroup_by_
fonction qui peut prendre des arguments de chaîne. Cette vignette décrit en détail la syntaxe de ces fonctions.L'extrait suivant résout proprement le problème que @sharoz posait à l'origine (notez la nécessité d'écrire l'
.dots
argument):(Notez que dplyr utilise maintenant l'
%>%
opérateur, et%.%
est obsolète).la source
Jusqu'à ce que dplyr ait un support complet pour les arguments de chaîne, peut-être que l'essentiel est utile:
https://gist.github.com/skranz/9681509
Il contient un tas de fonctions wrapper comme s_group_by, s_mutate, s_filter, etc. qui utilisent des arguments de chaîne. Vous pouvez les mélanger avec les fonctions normales de dplyr. Par exemple
la source
Cela fonctionne si vous lui passez les objets (enfin, vous n'êtes pas, mais ...) plutôt que comme vecteur de caractères:
où
df
était votredata
.?group_by
dit:ce que j'interprète comme ne signifiant pas les versions de caractère des noms, mais comment vous y feriez référence
foo$bar
;bar
n'est pas cité ici. Ou comment vous faites référence à des variables dans une formule:foo ~ bar
.@Arun mentionne également que vous pouvez faire:
Mais tu ne peux pas transmettre quelque chose qui n'a pas été évalué n'est pas n'est pas le nom d'une variable dans l'objet de données.
Je suppose que cela est dû aux méthodes internes que Hadley utilise pour rechercher les choses que vous transmettez via l'
...
argument.la source
la source
Un (minuscule) cas qui manque dans les réponses ici, que je voulais rendre explicite, est celui où les variables à regrouper sont générées dynamiquement au milieu d'un pipeline:
Cela montre essentiellement comment utiliser
grep
en conjonction avecgroup_by_(.dots = ...)
pour y parvenir.la source
Exemple général d'utilisation de l'
.dots
argument comme entrée de vecteur de caractère dans ladplyr::group_by
fonction:Ou sans nom codé en dur pour la variable de regroupement (comme demandé par l'OP):
Avec l'exemple de l'OP:
Voir aussi la vignette de dplyr sur la programmation qui explique les pronoms, la quasiquotation, les quosures et tidyeval.
la source