用准引号将参数列表传递给函数

slh*_*hck 3 r dplyr tidyeval

我试图用R编写一个函数,该函数根据分组变量汇总数据帧。分组变量作为列表给出并传递给group_by_at,我想对其进行参数化。

我现在正在做的是这样的:

library(tidyverse)

d = tribble(
  ~foo, ~bar, ~baz,
  1, 2, 3,
  1, 3, 5
  4, 5, 6,
  4, 5, 1
)

sum_fun <- function(df, group_vars, sum_var) {
  sum_var = enquo(sum_var)
  return(
    df %>% 
      group_by_at(.vars = group_vars) %>% 
      summarize(sum(!! sum_var))
  )
}

d %>% sum_fun(group_vars = c("foo", "bar"), baz)
Run Code Online (Sandbox Code Playgroud)

但是,我想这样调用该函数:

d %>% sum_fun(group_vars = c(foo, bar), baz)
Run Code Online (Sandbox Code Playgroud)

这意味着不应在调用中评估分组变量,而应在函数中评估分组变量。我将如何重写该功能以启用该功能?

我试过enquo像summary变量一样使用,然后替换group_vars!! group_vars,但这会导致此错误:

Error in !group_vars : invalid argument type
Run Code Online (Sandbox Code Playgroud)

使用group_by(!!!group_vars)收益:

Column `c(foo, bar)` must be length 2 (the number of rows) or one, not 4 
Run Code Online (Sandbox Code Playgroud)

重写函数的正确方法是什么?

Tun*_*ung 6

我只是vars用来做报价。这是使用mtcars数据集的示例

library(tidyverse)

sum_fun <- function(.data, .summary_var, .group_vars) {
  summary_var <- enquo(.summary_var)

  .data %>%
    group_by_at(.group_vars) %>%
    summarise(mean = mean(!!summary_var))
}

sum_fun(mtcars, disp, .group_vars = vars(cyl, am))
#> # A tibble: 6 x 3
#> # Groups:   cyl [?]
#>     cyl    am  mean
#>   <dbl> <dbl> <dbl>
#> 1     4     0 136. 
#> 2     4     1  93.6
#> 3     6     0 205. 
#> 4     6     1 155  
#> 5     8     0 358. 
#> 6     8     1 326
Run Code Online (Sandbox Code Playgroud)

您也可以替换.group_vars...(点-点-点)

sum_fun2 <- function(.data, .summary_var, ...) {
  summary_var <- enquo(.summary_var)

  .data %>%
    group_by_at(...) %>%  # Forward `...`
    summarise(mean = mean(!!summary_var))
}

sum_fun2(mtcars, disp, vars(cyl, am))
#> # A tibble: 6 x 3
#> # Groups:   cyl [?]
#>     cyl    am  mean
#>   <dbl> <dbl> <dbl>
#> 1     4     0 136. 
#> 2     4     1  93.6
#> 3     6     0 205. 
#> 4     6     1 155  
#> 5     8     0 358. 
#> 6     8     1 326
Run Code Online (Sandbox Code Playgroud)

如果你喜欢电源输入为列的列表,你将需要使用enquos...

sum_fun3 <- function(.data, .summary_var, ...) {
  summary_var <- enquo(.summary_var)

  group_var <- enquos(...)
  print(group_var)

  .data %>%
      group_by_at(group_var) %>% 
      summarise(mean = mean(!!summary_var))
}

sum_fun3(mtcars, disp, c(cyl, am))
#> [[1]]
#> <quosure>
#>   expr: ^c(cyl, am)
#>   env:  global
#> 
#> # A tibble: 6 x 3
#> # Groups:   cyl [?]
#>     cyl    am  mean
#>   <dbl> <dbl> <dbl>
#> 1     4     0 136. 
#> 2     4     1  93.6
#> 3     6     0 205. 
#> 4     6     1 155  
#> 5     8     0 358. 
#> 6     8     1 326
Run Code Online (Sandbox Code Playgroud)

编辑:将附加.addi_var.../ .group_var

sum_fun4 <- function(.data, .summary_var, .addi_var, .group_vars) {
  summary_var <- enquo(.summary_var)

  .data %>%
    group_by_at(c(.group_vars, .addi_var)) %>%
    summarise(mean = mean(!!summary_var))
}

sum_fun4(mtcars, disp, .addi_var = vars(gear), .group_vars = vars(cyl, am))
#> # A tibble: 10 x 4
#> # Groups:   cyl, am [?]
#>      cyl    am  gear  mean
#>    <dbl> <dbl> <dbl> <dbl>
#>  1     4     0     3 120. 
#>  2     4     0     4 144. 
#>  3     4     1     4  88.9
#>  4     4     1     5 108. 
#>  5     6     0     3 242. 
#>  6     6     0     4 168. 
#>  7     6     1     4 160  
#>  8     6     1     5 145  
#>  9     8     0     3 358. 
#> 10     8     1     5 326
Run Code Online (Sandbox Code Playgroud)

group_by_at() 也可以将输入作为列名的字符向量

sum_fun5 <- function(.data, .summary_var, .addi_var, ...) {

  summary_var <- enquo(.summary_var)
  addi_var    <- enquo(.addi_var)
  group_var   <- enquos(...)

  ### convert quosures to strings for `group_by_at`
  all_group <- purrr::map_chr(c(addi_var, group_var), quo_name)

  .data %>%
    group_by_at(all_group) %>% 
    summarise(mean = mean(!!summary_var))
}

sum_fun5(mtcars, disp, gear, cyl, am)
#> # A tibble: 10 x 4
#> # Groups:   gear, cyl [?]
#>     gear   cyl    am  mean
#>    <dbl> <dbl> <dbl> <dbl>
#>  1     3     4     0 120. 
#>  2     3     6     0 242. 
#>  3     3     8     0 358. 
#>  4     4     4     0 144. 
#>  5     4     4     1  88.9
#>  6     4     6     0 168. 
#>  7     4     6     1 160  
#>  8     5     4     1 108. 
#>  9     5     6     1 145  
#> 10     5     8     1 326
Run Code Online (Sandbox Code Playgroud)

reprex软件包(v0.2.1.9000)创建于2018-10-09