web-dev-qa-db-fra.com

dplyr: Comment utiliser group_by dans une fonction?

Je veux utiliser utiliser le dplyr::group_by fonction à l'intérieur d'une autre fonction, mais je ne sais pas comment passer les arguments à cette fonction.

Quelqu'un peut-il fournir un exemple de travail?

library(dplyr)
data(iris)
iris %.% group_by(Species) %.% summarise(n = n()) # 
## Source: local data frame [3 x 2]
##      Species  n
## 1  virginica 50
## 2 versicolor 50
## 3     setosa 50

mytable0 <- function(x, ...) x %.% group_by(...) %.% summarise(n = n())
mytable0(iris, "Species") # OK
## Source: local data frame [3 x 2]
##      Species  n
## 1  virginica 50
## 2 versicolor 50
## 3     setosa 50

mytable1 <- function(x, key) x %.% group_by(as.name(key)) %.% summarise(n = n())
mytable1(iris, "Species") # Wrong!
# Error: unsupported type for column 'as.name(key)' (SYMSXP)

mytable2 <- function(x, key) x %.% group_by(key) %.% summarise(n = n())
mytable2(iris, "Species") # Wrong!
# Error: index out of bounds
43

Pour la programmation, group_by_ Est l'équivalent de group_by:

library(dplyr)

mytable <- function(x, ...) x %>% group_by_(...) %>% summarise(n = n())
mytable(iris, "Species")
# or iris %>% mytable("Species")

qui donne:

     Species  n
1     setosa 50
2 versicolor 50
3  virginica 50

Mise à jour Au moment où cela a été écrit, dplyr a utilisé %.% Qui est ce qui était initialement utilisé ci-dessus mais maintenant %>% Est préféré, donc nous avons changé ci-dessus pour que cela reste pertinent.

pdate 2 regroup est maintenant obsolète, utilisez plutôt group_by_.

pdategroup_by_(list(...)) devient désormais group_by_(...) dans la nouvelle version de dplyr selon le commentaire de Roberto.

pdate 4 Ajout d'une variante mineure suggérée dans les commentaires.

pdate 5: Avec rlang/tidyeval il est maintenant possible de faire ceci:

library(rlang)
mytable <- function(x, ...) {
  group_ <- syms(...)
  x %>% 
    group_by(!!!group_) %>% 
    summarise(n = n())
}
mytable(iris, "Species")

ou en passant Species non évalué, c'est-à-dire sans guillemets:

library(rlang)
mytable <- function(x, ...) {
  group_ <- quos(...)
  x %>% 
    group_by(!!!group_) %>% 
    summarise(n = n())
}
mytable(iris, Species)
62
G. Grothendieck

[~ # ~] mise à jour [~ # ~] : à partir de dplyr 0.7.0, vous pouvez utiliser une évaluation soignée pour accomplir cela.

Voir http://dplyr.tidyverse.org/articles/programming.html pour plus de détails.

library(tidyverse)
data("iris")

my_table <- function(df, group_var) {
  group_var <- enquo(group_var)      # Create quosure
  df %>% 
    group_by(!!group_var) %>%        # Use !! to unquote the quosure
    summarise(n = n())
}

my_table(iris, Species)

> my_table(iris, Species)
# A tibble: 3 x 2
     Species     n
      <fctr> <int>
1     setosa    50
2 versicolor    50
3  virginica    50
7
Brad Cannell

Moche comme ils viennent, mais elle travaille:

mytable3 <- function(x, key) {
  my.call <- bquote(summarise(group_by(.(substitute(x)), NULL), n = n()))
  my.call[[2]][[3]] <- as.name(key)
  eval(my.call, parent.frame())
} 
mytable3(iris, "Species")
# Source: local data frame [3 x 2]
#
#      Species  n
# 1  virginica 50
# 2 versicolor 50
# 3     setosa 50

Il y a presque certainement des cas qui provoqueront une rupture, mais vous avez compris. Je ne pense pas que vous puissiez vous débrouiller avec l'appel. Une autre chose qui a fonctionné mais qui était encore plus laide est:

mytable4 <- function(x, key) summarise(group_by(x, x[[key]]), n = n())
2
BrodieG