代码之家  ›  专栏  ›  技术社区  ›  Stefano

函数中包含列名列表的Tidyeval

  •  2
  • Stefano  · 技术社区  · 7 年前

    我试图创建一个函数,将列名列表传递给 dplyr 作用如果列名称列表在 ... 表格,如 tidyeval 文档:

    df <- tibble(
      g1 = c(1, 1, 2, 2, 2),
      g2 = c(1, 2, 1, 2, 1),
      a = sample(5), 
      b = sample(5)
    )
    
    my_summarise <- function(df, ...) {
      group_var <- quos(...)
    
      df %>%
        group_by(!!!group_var) %>%
        summarise(a = mean(a))
    }
    
    my_summarise(df, g1, g2)
    

    但是,如果我想将列名列出来作为函数的参数,那么上述解决方案将不起作用(当然):

    my_summarise <- function(df, group_var, sum_var) {
      group_var <- quos(group_var) # nor enquo(group_var)
      sum_var <- enquo(sum_var)
    
      df %>%
        group_by(!!!group_var) %>%
        summarise(a = mean(a))
    }
    
    my_summarise(df, list(g1, g2), a)
    my_summarise(df, list(g1, g2), b)
    

    如何让列表中的项目单独报价?

    这个问题类似于 Passing dataframe column names in a function inside another function 但在评论中,建议使用字符串,而在这里,我希望使用裸列名。

    2 回复  |  直到 7 年前
        1
  •  4
  •   AlphaDrivers    7 年前
    library(dplyr)
    
    df <- tibble(
      g1 = c(1, 1, 2, 2, 2),
      g2 = c(1, 2, 1, 2, 1),
      a = sample(5), 
      b = sample(5)
    )
    
    my_summarise = function(df, group_var, fun_name) {
    
      df %>%
        group_by(!!! group_var) %>%
        summarize_all(fun_name)
    }
    
    my_summarise(df, alist(g1, g2), mean)
    

    alist()将参数“g1”和“g2”作为函数参数处理(不计算它们),而!!!(与UQS()相同)取消引用并拼接列表。sum\u var不是必需的,因为您似乎希望取“a”和“b”的平均值。此外,还可以通过传入函数来对其进行泛化。

        2
  •  1
  •   aosmith    7 年前

    您可以使用 alist 而不是 list ,因为它不会计算参数。

    my_summarise = function(df, group_var, sum_var) {
        group_var = quos(!!! group_var)
        sum_var = enquo(sum_var)
    
        df %>%
            group_by(!!! group_var) %>%
            summarise(!! quo_name( sum_var) := mean( !! sum_var) )
    }
    
    my_summarise(df, alist(g1, g2), b)
    
    # A tibble: 4 x 3
    # Groups:   g1 [?]
         g1    g2     b
      <dbl> <dbl> <dbl>
    1     1     1   2.0
    2     1     2   3.0
    3     2     1   4.5
    4     2     2   1.0
    

    另一种选择是直接通过 quos 而不是 列表 如图所示 in this answer ,从而避免了一些并发症。

    my_summarise = function(df, group_var, sum_var) {
        # group_var = quos(!!! group_var)
        sum_var = enquo(sum_var)
    
        df %>%
            group_by(!!! group_var) %>%
            summarise(!! quo_name( sum_var) := mean( !! sum_var) )
    }
    
    my_summarise(df, quos(g1, g2), b)
    
    # A tibble: 4 x 3
    # Groups:   g1 [?]
         g1    g2     b
      <dbl> <dbl> <dbl>
    1     1     1   2.0
    2     1     2   3.0
    3     2     1   4.5
    4     2     2   1.0