Dplyr: 将公式作为对象输入 summarise()

创建于 2018-04-25  ·  4评论  ·  资料来源: tidyverse/dplyr

我花了相当多的时间阅读(以及重读和重读)NSE 和 dplyr 编程的各种解释,但未能解决看起来应该是一个简单问题的问题。 我想提前定义汇总公式,然后编写一个函数将这些公式输入 summarise() 进行评估。

这样做的动机是构建一个特定于一组数据的包,以不需要用户记住的标准方式设置该数据的复杂聚合,但允许他们快速轻松地提取数据和通过只记住聚合的名称来正确聚合它。

这是我的意思的一个例子:

price_per_carat <- ~ sum(price) / sum(carat)
price_depth_ratio <- ~ sum(price) / sum(depth)

summarise_as <- function(.data, ...) {
  # some kind of black magic
}

diamonds %>%
  group_by(cut, clarity)
  summarise_as(price_per_carat, price_depth_ratio)

# A tibble: 40 x 4
# Groups:   cut [?]
     cut clarity price_per_carat price_depth_ratio
   <ord>   <ord>           <dbl>             <dbl>
 1  Fair      I1        2721.185          56.37119
 2  Fair     SI2        4297.840          80.31302
 3  Fair     SI1        4362.573          65.84666
 4  Fair     VS2        4715.875          65.60159
 5  Fair     VS1        4734.064          66.17081
 6  Fair    VVS2        4843.546          53.29967
 7  Fair    VVS1        5824.159          64.07653
 8  Fair      IF        4030.679          31.83685
 9  Good      I1        2989.670          57.94697
10  Good     SI2        4424.404          73.58696
# ... with 30 more rows

如果不是很清楚,我基本上是想找到一种方法让summarise_as(price_per_carat, price_depth_ratio)表现得像我输入的summarise(price_per_carat = sum(price) / sum(carat), price_depth_ratio = sum(price) / sum(depth))

我尝试了各种形式的 quo()、enquo()、as.formula、deparse(substitute()) 等,试图让它工作,但都失败了。 这样做的正确方法是什么?

最有用的评论

也许这更容易:

library(tidyverse)
library(rlang)
#> 
#> Attaching package: 'rlang'
#> The following objects are masked from 'package:purrr':
#> 
#>     %@%, %||%, as_function, flatten, flatten_chr, flatten_dbl,
#>     flatten_int, flatten_lgl, invoke, list_along, modify, prepend,
#>     rep_along, splice

exprs <- list( 
  price_per_carat = expr(sum(price) / sum(carat)), 
  price_depth_ratio = expr(sum(price) / sum(depth))
)

diamonds %>%
  group_by(cut, clarity) %>%
  summarise(!!!exprs)
#> # A tibble: 40 x 4
#> # Groups:   cut [?]
#>    cut   clarity price_per_carat price_depth_ratio
#>    <ord> <ord>             <dbl>             <dbl>
#>  1 Fair  I1                2721.              56.4
#>  2 Fair  SI2               4298.              80.3
#>  3 Fair  SI1               4363.              65.8
#>  4 Fair  VS2               4716.              65.6
#>  5 Fair  VS1               4734.              66.2
#>  6 Fair  VVS2              4844.              53.3
#>  7 Fair  VVS1              5824.              64.1
#>  8 Fair  IF                4031.              31.8
#>  9 Good  I1                2990.              57.9
#> 10 Good  SI2               4424.              73.6
#> # ... with 30 more rows

reprex 包(v0.2.0) 于

所有4条评论

如果您想使用公式,这是一种方法:

library(tidyverse)
library(rlang)
#> 
#> Attaching package: 'rlang'
#> The following objects are masked from 'package:purrr':
#> 
#>     %@%, %||%, as_function, flatten, flatten_chr, flatten_dbl,
#>     flatten_int, flatten_lgl, invoke, list_along, modify, prepend,
#>     rep_along, splice

summarise_as <- function(.data, ...) {
  dots  <- quos(...)
  names <- map_chr(dots, ~as.character(quo_get_expr(.x)))
  names(dots) <- names

  get_expr <- function(q){
    formula <- eval_tidy(quo_get_expr(q), quo_get_env(q))
    expr(!!formula[[2]])
  }

  exprs <- map( dots, get_expr)
  summarise(.data, !!!exprs)
}

price_per_carat <- ~ sum(price) / sum(carat)
price_depth_ratio <- ~ sum(price) / sum(depth)

diamonds %>%
  group_by(cut, clarity) %>%
  summarise_as(price_per_carat, price_depth_ratio)
#> # A tibble: 40 x 4
#> # Groups:   cut [?]
#>    cut   clarity price_per_carat price_depth_ratio
#>    <ord> <ord>             <dbl>             <dbl>
#>  1 Fair  I1                2721.              56.4
#>  2 Fair  SI2               4298.              80.3
#>  3 Fair  SI1               4363.              65.8
#>  4 Fair  VS2               4716.              65.6
#>  5 Fair  VS1               4734.              66.2
#>  6 Fair  VVS2              4844.              53.3
#>  7 Fair  VVS1              5824.              64.1
#>  8 Fair  IF                4031.              31.8
#>  9 Good  I1                2990.              57.9
#> 10 Good  SI2               4424.              73.6
#> # ... with 30 more rows

也许@lionel- 有更好的方法

也许这更容易:

library(tidyverse)
library(rlang)
#> 
#> Attaching package: 'rlang'
#> The following objects are masked from 'package:purrr':
#> 
#>     %@%, %||%, as_function, flatten, flatten_chr, flatten_dbl,
#>     flatten_int, flatten_lgl, invoke, list_along, modify, prepend,
#>     rep_along, splice

exprs <- list( 
  price_per_carat = expr(sum(price) / sum(carat)), 
  price_depth_ratio = expr(sum(price) / sum(depth))
)

diamonds %>%
  group_by(cut, clarity) %>%
  summarise(!!!exprs)
#> # A tibble: 40 x 4
#> # Groups:   cut [?]
#>    cut   clarity price_per_carat price_depth_ratio
#>    <ord> <ord>             <dbl>             <dbl>
#>  1 Fair  I1                2721.              56.4
#>  2 Fair  SI2               4298.              80.3
#>  3 Fair  SI1               4363.              65.8
#>  4 Fair  VS2               4716.              65.6
#>  5 Fair  VS1               4734.              66.2
#>  6 Fair  VVS2              4844.              53.3
#>  7 Fair  VVS1              5824.              64.1
#>  8 Fair  IF                4031.              31.8
#>  9 Good  I1                2990.              57.9
#> 10 Good  SI2               4424.              73.6
#> # ... with 30 more rows

reprex 包(v0.2.0) 于

我现在就关闭这个。 也许考虑https://community.rstudio.com的问题不仅仅是问题。

这个老问题已自动锁定。 如果您认为您发现了相关问题,请提交一个新问题(使用 reprex)并链接到此问题。 https://reprex.tidyverse.org/

此页面是否有帮助?
0 / 5 - 0 等级