首页 文章

dplyr:如何在函数中使用group_by?

提问于
浏览
39

我想在另一个函数中使用 dplyr::group_by 函数,但我不知道如何将参数传递给这个函数 .

有人能提供一个有效的例子吗?

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

3 回答

  • 2

    对于编程, group_by_group_by 的对应物:

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

    这使:

    Species  n
    1     setosa 50
    2 versicolor 50
    3  virginica 50
    

    Update 在写这篇文章的时候,dplyr使用了 %.% 这是上面最初使用的,但是现在 %>% 是有利的,所以为了保持这种相关性已经改变了 .

    现在不推荐使用 Update 2 regroup,而是使用group_by_ .

    根据Roberto的评论, Update 3 group_by_(list(...)) 现在在dplyr的新版本中成为 group_by_(...) .

    Update 4 在评论中建议添加了小的变体 .

    Update 5: 使用rlang / tidyeval,现在可以这样做:

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

    或传递 Species 未评估,即没有报价:

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

    UPDATE :从dplyr 0.7.0开始,您可以使用整齐的eval来完成此任务 .

    有关详细信息,请参阅http://dplyr.tidyverse.org/articles/programming.html .

    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
    
  • 56

    他们来的时候很难看,但她工作:

    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
    

    几乎可以肯定会导致这种情况破裂,但你明白了 . 我认为你不能搞砸这个电话 . 另一件事确实有效,但更加丑陋的是:

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

相关问题