【问题标题】:R dplyr: how to use ... with summarize(across()) when ... will refer to a variable name within the data?R dplyr:当 ... 将引用数据中的变量名称时,如何将 ... 与 summarise(across()) 一起使用?
【发布时间】:2021-02-22 23:22:25
【问题描述】:

我想有一个使用summarize的灵活函数,其中:

  1. 聚合函数由用户给出
  2. 聚合函数可能会使用更多参数来引用数据本身中的变量。

一个很好的例子是用户提供fun=weighted.mean() 并指定权重参数w

目前,我正在尝试使用...。问题是我找不到让... 引用数据框中的变量的方法?下面的示例是使用across() 给出的,但如果我使用summarize_at() 代替,也会发生同样的情况

谢谢!!

library(tidyverse)
fo1 <- function(df, fun=mean, ...){
  df %>% 
    group_by(Species) %>% 
    summarise(across(starts_with("sepal"), fun, ...))
}

fo1(iris)
#> `summarise()` ungrouping output (override with `.groups` argument)
#> # A tibble: 3 x 3
#>   Species    Sepal.Length Sepal.Width
#>   <fct>             <dbl>       <dbl>
#> 1 setosa             5.01        3.43
#> 2 versicolor         5.94        2.77
#> 3 virginica          6.59        2.97
fo1(iris, fun=weighted.mean)
#> `summarise()` ungrouping output (override with `.groups` argument)
#> # A tibble: 3 x 3
#>   Species    Sepal.Length Sepal.Width
#>   <fct>             <dbl>       <dbl>
#> 1 setosa             5.01        3.43
#> 2 versicolor         5.94        2.77
#> 3 virginica          6.59        2.97
fo1(iris, fun=weighted.mean, w=Petal.Length)
#> Error: Problem with `summarise()` input `..1`.
#> x object 'Petal.Length' not found
#> ℹ Input `..1` is `across(starts_with("sepal"), fun, ...)`.
#> ℹ The error occurred in group 1: Species = "setosa".
fo1(iris, fun=weighted.mean, w=.data$Petal.Length)
#> Error: Problem with `summarise()` input `..1`.
#> x 'x' and 'w' must have the same length
#> ℹ Input `..1` is `across(starts_with("sepal"), fun, ...)`.
#> ℹ The error occurred in group 1: Species = "setosa".

reprex package (v0.3.0) 于 2020 年 11 月 10 日创建

【问题讨论】:

    标签: r dplyr tidyverse rlang across


    【解决方案1】:

    您需要传递附加参数的确切值。 .data$Petal.LengthNULL

    library(dplyr)
    
    fo1 <- function(df, fun=mean, ...){
      df %>% 
        summarise(across(starts_with("sepal"), fun, ...))
    }
    
    
    fo1(iris, fun=weighted.mean, w= iris$Petal.Length)
    #  Sepal.Length Sepal.Width
    #1     6.180167    2.970197
    

    【讨论】:

    • 感谢罗纳克!不幸的是,如果数据被分组,这将失败!我更新了示例以明确该约束。
    • 我明白了。对,那是真的。但我认为weighted.mean 是一个独特的例子,我们有额外的向量形式的参数。通常,附加参数的形式为na.rm = TRUE,可以直接与...一起应用。
    • summarize 中使用!!!enquos(...) 而不是...。然后它可以处理iris %&gt;% group_by(Species) %&gt;% fo1(fun = weighted.mean, w = Petal.Length, na.rm = TRUE)
    • @Paul:这绝对是迄今为止最好的解决方案。
    • @Paul 我认为您实际上得到了答案!想让您的评论成为答案吗?
    【解决方案2】:

    这很难看,但有效。

    > fo1 <- function(df, fun=mean, ...){
    +   w <- df %>% pull(...)
    +   df %>% 
    +     summarise(across(starts_with("Sepal"), fun, w))
    + }
    > fo1(iris, fun=weighted.mean, Petal.Length)
      Sepal.Length Sepal.Width
    1     6.180167    2.970197
    

    根据上面 cmets 中 Paul 的建议,这似乎是一个通用的解决方案:

    fo1 <- function(df, fun=mean, ...){
      df %>% 
        summarise(across(starts_with("Sepal"), fun, !!!enquos(...)))
    }
    > fo1(iris, fun=weighted.mean, Petal.Length)
      Sepal.Length Sepal.Width
    1     6.180167    2.970197
    > fo1(iris, fun=mean)
      Sepal.Length Sepal.Width
    1     5.843333    3.057333
    

    我尝试了!!!!!enquo()enquos() 的几种组合,但一定错过了。

    【讨论】:

    • 感谢 Limey!不幸的是,这假设 w 始终存在,但如果使用不需要它的函数,则会失败!
    • 我同意。这就是它丑陋的原因! :)
    【解决方案3】:

    enquos 将返回引用表达式的列表。取消引用拼接运算符!!! 将取消引用每个元素作为函数调用的参数。

    library(tidyverse)
    
    fo1 <- function(df, fun = mean, ...) {
      df %>% 
        summarise(across(starts_with("sepal"), fun, !!!enquos(...)))
    }
    
    iris %>%
      group_by(Species) %>%
      fo1(fun = weighted.mean, w = Petal.Length, na.rm = TRUE)
    #> # A tibble: 3 x 3
    #>   Species    Sepal.Length Sepal.Width
    #>   <fct>             <dbl>       <dbl>
    #> 1 setosa             5.02        3.44
    #> 2 versicolor         5.98        2.79
    #> 3 virginica          6.64        2.99
    

    请参阅here 了解更多信息。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-05-16
      • 2021-04-20
      • 2017-09-10
      • 2021-10-03
      • 2020-12-07
      • 2020-08-30
      • 1970-01-01
      • 2023-03-29
      相关资源
      最近更新 更多