让 quosures 在 map 调用中工作

Getting quosures to work inside a map call

我正在努力让 quosures 在 map 调用中工作。

一些玩具数据:

library(tidyverse)

df <- tibble(
   g1 = letters[1:2] %>% 
     rep(each = 3),
   g2 = letters[3:5] %>% 
     rep(times = 2),
   y = runif(6)
  )

我可以让这个函数工作,在我将它传递给 group_by 之前我 enquo 一个变量:

sum1 <- function(df, g){

 g <- enquo(g)

 df %>% 
   group_by(!! g) %>% 
   summarize(
     mu = y %>% 
       mean
     )
  }

调用这个函数

 sum1(df, g2)

让我得到了预期的结果。但是如果我想 map 多个分组变量,(即 g1 & g2

 str_c("g", 1:2) %>% 
   map(
    function(i)
      sum1(df, i)
   )

Returns错误

  Error in grouped_df_impl(data, unname(vars), drop) : 
   Column `i` is unknown 

如何在 map 通话中设置 quosures

我们可以使用group_by_at,它可以接受一个字符串作为参数

library(tidyverse)
sum1 <- function(df, grps){

 map(grps, ~ 
           df %>%
              group_by_at(.x) %>%
              summarise(mu = mean(y))
              )

              }

sum1(df, str_c("g", 1:2))
#[[1]]
# A tibble: 2 x 2
#  g1       mu
#  <chr> <dbl>
#1 a     0.440
#2 b     0.469

#[[2]]
# A tibble: 3 x 2
#  g2       mu
#  <chr> <dbl>
#1 c     0.528
#2 d     0.592
#3 e     0.243

关于函数中带quosure的参数的用法,不清楚应该是单参数还是多参数

如果我们将字符串作为参数,将其转换为符号 (sym) 然后计算 (!!)

sum2 <- function(df, grps){


 map(grps, ~ 
           df %>%
              group_by(!! rlang::sym(.x)) %>%
              summarise(mu = mean(y))
              )

              }

sum2(df, str_c("g", 1:2))
#[[1]]
# A tibble: 2 x 2
#  g1       mu
#  <chr> <dbl>
#1 a     0.440
#2 b     0.469

#[[2]]
# A tibble: 3 x 2
#  g2       mu
#  <chr> <dbl>
#1 c     0.528
#2 d     0.592
#3 e     0.243

另一个有资格通过多个组的是

sum3 <- function(df, ...){

   gs <- enquos(...)
   map(gs, ~ 
         df %>%
            group_by(!! .x) %>%
            summarise(mu = mean(y)))


              }
sum3(df, g1, g2)
#[[1]]
# A tibble: 2 x 2
#  g1       mu
#  <chr> <dbl>
#1 a     0.440
#2 b     0.469

#[[2]]
# A tibble: 3 x 2
#  g2       mu
#  <chr> <dbl>
#1 c     0.528
#2 d     0.592
#3 e     0.243
str_c("g", 1:2) %>% 
  syms() %>%
  map(sum1, df = df)

syms()character 转换为符号(sum1 所期望的)。

map(function(i) sum1(df, i)) 重写为 map(sum1, df = df) 可防止在 sum1 包含在另一个函数中时对承诺 i 进行不必要的评估。

map(function(i) sum1(df, i))重写为map(sum1, df = df)允许将符号g1g2直接传递给sum1(),而不是符号i .

(或者,str_c("g", 1:2) %>% syms() %>% map(function(i) sum1(df, !! i))str_c("g", 1:2) %>% map(function(i) sum1(df, !! sym(i))) 工作,其中 !! 在将 i 传递给 sum1() 之前取消引号。
(实际上这有点过于简单化了:在 之前 不会发生取消引用,但是当你在 sum1 的正文中执行 enquo(g) 时)。