【问题标题】:R user-defined/dynamic summary function within dplyr::summarisedplyr::summarise 中的 R 用户定义/动态汇总函数
【发布时间】:2020-11-04 10:38:49
【问题描述】:

如果听起来没有很多类似的问题,很难定义这个问题!

我有一个函数,我希望其中一个参数是函数名,它将传递给 dplyr::summarise,例如“平均值”或“总和”:

data(mtcars)
  f <- function(x = mtcars,
                groupcol = "cyl",
                zCol = "disp",
                zFun = "mean") {
    
    zColquo = quo_name(zCol)
    
    cellSummaries <- x %>%
      group_by(gear, !!sym(groupcol)) %>% # 1 preset grouper, 1 user-defined
      summarise(Count = n(), # 1 preset summary, 1 user defined
                !!zColquo := mean(!!sym(zColquo))) # mean should be zFun, user-defined
    ungroup
  }

(这个按齿轮和圆柱分组,然后返回,每组,计数和平均值(disp))

根据我的说明,我希望“意思”是动态的,执行 zFun 定义的功能,但我终生无法弄清楚如何去做!提前感谢您的任何建议。

【问题讨论】:

    标签: r function dplyr non-standard-evaluation


    【解决方案1】:

    您可以使用match.fun 使函数动态化。我还删除了zColquo,因为它不需要。

    library(dplyr)
    library(rlang)
    
    f <- function(x = mtcars,
                  groupcol = "cyl",
                  zCol = "disp",
                  zFun = "mean") {
    
      cellSummaries <- x %>%
                       group_by(gear, !!sym(groupcol)) %>% 
                       summarise(Count = n(), 
                                 !!zCol := match.fun(zFun)(!!sym(zCol))) %>%
                       ungroup
    
      return(cellSummaries)
    }
    

    然后您可以检查输出

    f()
    
    # A tibble: 8 x 4
    #   gear   cyl Count  disp
    #  <dbl> <dbl> <int> <dbl>
    #1     3     4     1  120.
    #2     3     6     2  242.
    #3     3     8    12  358.
    #4     4     4     8  103.
    #5     4     6     4  164.
    #6     5     4     2  108.
    #7     5     6     1  145 
    #8     5     8     2  326 
    
    f(zFun = "sum")
    
    # A tibble: 8 x 4
    #   gear   cyl Count  disp
    #  <dbl> <dbl> <int> <dbl>
    #1     3     4     1  120.
    #2     3     6     2  483 
    #3     3     8    12 4291.
    #4     4     4     8  821 
    #5     4     6     4  655.
    #6     5     4     2  215.
    #7     5     6     1  145 
    #8     5     8     2  652 
    

    【讨论】:

    • 谢谢! match.fun() 比 get() 更好或更差的任何原因?
    • 我认为这只是一个选择问题。我通常将match.fun 用于函数。
    • 干杯,接受这个,因为你是第一个!似乎有几种方法可以给这只猫剥皮。
    【解决方案2】:

    我们可以使用get

    library(dplyr)    
    f <- function(x = mtcars,
                groupcol = "cyl",
                zCol = "disp",
                zFun = "mean") {
    
    
      zColquo = quo_name(zCol)
      x %>%
      group_by(gear, !!sym(groupcol)) %>% # 1 preset grouper, 1 user-defined
      summarise(Count = n(), # 1 preset summary, 1 user defined
                !!zColquo := get(zFun)(!!sym(zCol))) %>% 
    ungroup
     }
    
    f()
    # A tibble: 8 x 4
    #   gear   cyl Count  disp
    #  <dbl> <dbl> <int> <dbl>
    #1     3     4     1  120.
    #2     3     6     2  242.
    #3     3     8    12  358.
    #4     4     4     8  103.
    #5     4     6     4  164.
    #6     5     4     2  108.
    #7     5     6     1  145 
    #8     5     8     2  326 
    
    
    f(zFun = "sum")
    # A tibble: 8 x 4
    #   gear   cyl Count  disp
    #  <dbl> <dbl> <int> <dbl>
    #1     3     4     1  120.
    #2     3     6     2  483 
    #3     3     8    12 4291.
    #4     4     4     8  821 
    #5     4     6     4  655.
    #6     5     4     2  215.
    #7     5     6     1  145 
    #8     5     8     2  652 
    

    此外,如果我们用across 包装,我们可以删除group_bysummarise 中的sym 评估

    f <- function(x = mtcars,
                groupcol = "cyl",
                zCol = "disp",
                zFun = "mean") {
    
    
    
     x %>%
        group_by(across(c(gear, groupcol))) %>% # 1 preset grouper, 1 user-defined
        summarise(Count = n(), # 1 preset summary, 1 user defined
                across(zCol, ~ get(zFun)(.))) %>% 
        ungroup
     }
    f()
    # A tibble: 8 x 4
    #   gear   cyl Count  disp
    #  <dbl> <dbl> <int> <dbl>
    #1     3     4     1  120.
    #2     3     6     2  242.
    #3     3     8    12  358.
    #4     4     4     8  103.
    #5     4     6     4  164.
    #6     5     4     2  108.
    #7     5     6     1  145 
    #8     5     8     2  326 
    

    【讨论】:

    • @dez93_2000 您可以在zFun 中传递未引用的summean,然后您不需要任何其他功能,即zFun(!!sym(zCol))) 应该可以工作
    • 再次感谢。从未想过将 get() 用于函数!您的 cross() 方法很有趣 - 我仍在思考新的实现。
    • @dez93_2000 谢谢。使用across,您可以将多个函数传递给列块,默认情况下,它将返回相同的列名。因此,一些评估可以简化
    • 这是我听说时最吸引人的地方;让我感兴趣的是 1. 为什么在 group_by 中使用 cross 可以消除对 !!sym() groupcol 的需要,以及 2. cross 的第二次使用是顶级魔法!波浪号是 purrr 风格吗?似乎 cross(zCol, get(zFun)) 应该可以工作??
    • @dez93_2000 在summarise 中,您可以使用多个列,例如summarise(across(c(Zcol, Zcol2), ~ get(zFun)(.))~ 用于 lambda 函数 function(x)
    猜你喜欢
    • 2016-11-30
    • 1970-01-01
    • 2021-05-07
    • 2020-12-27
    • 1970-01-01
    • 2021-01-25
    • 2022-01-23
    • 2021-11-30
    • 2017-01-08
    相关资源
    最近更新 更多