R rlang:处理 NULL 参数?

R rlang: handle NULL arguments?

我想将默认值为 NULL 的可选参数用于 dplyr 函数(比如 count())。如果我将标准过程与 !!enquo() 一起使用,我会收到错误消息:错误:列 NULL 未知

有趣的是,rlang/tidyverse 允许缺失值,所以如果 NULL 可以转换为缺失值,但看起来很脏(特别是如果我想在之后使用 facet_grid,那接受NULL 但不丢失)。

library(tidyverse)
df <- tibble(a = sample(LETTERS[1:2], 100, replace = TRUE), 
             b = sample(LETTERS[3:4], 100, replace = TRUE), 
             value = rnorm(100,5,1))

f2 <- function(df, group_var1=a,  group_var2=NULL, group_var3) {
  res <- df %>%
    count({{group_var1}}, {{group_var2}}, {{group_var3}})

  print(res)
  ggplot(aes(x=a, y=n), data = res)+
    geom_col() +
    facet_grid(row= enquo(group_var2))
}

f2(df, group_var1 = a, group_var2=b)
#> # A tibble: 4 x 3
#>   a     b         n
#>   <chr> <chr> <int>
#> 1 A     C        26
#> 2 A     D        29
#> 3 B     C        16
#> 4 B     D        29


f2(df, group_var1 = a)
#> Error: Column `NULL` is unknown

reprex package (v0.3.0)

于 2019-08-04 创建

group_bycount 都不会接受 NULL 值。因此,您必须首先使用 enquos 创建一个 quosures 对象,并对 NULL 值进行子集化。由于 count 只是 tallygroup_by 的包装器,我们可以使用 group_by.[=28 的 group_by_at 范围版本手动分组和计数=]

f2 <- function(df, group_var1=a,  group_var2=NULL, group_var3) {

grps <- enquos(a = group_var1, b = group_var2, c = group_var3, .ignore_empty = "all")

  # this removes the NULL values

  grps <- grps[map_lgl(grps, ~ !quo_is_null(.))]

  res <- df %>%
    group_by_at(grps) %>% 
    tally() %>% 
    ungroup()

  print(res) 
}

这很好地创建了 res 数据框:

> f2(df, group_var1 = a, group_var2=b)
# A tibble: 4 x 3
  a     b         n
  <chr> <chr> <int>
1 A     C        20
2 A     D        30
3 B     C        22
4 B     D        28
> f2(df, group_var1 = a)
# A tibble: 2 x 2
  a         n
  <chr> <int>
1 A        50
2 B        50

然而,我们在尝试创建剧情时又遇到了问题。 enquo 创建了一个带引号的对象,所以 NULL 变成了 "NULL" (更准确地说是 `NULL`),所以 ggplot 不知道如何处理它。所以我认为条件语句是可行的方法:

f2 <- function(df, group_var1=a,  group_var2=NULL, group_var3) {

  grps <- enquos(a = group_var1, b = group_var2, c = group_var3, .ignore_empty = "all")

  grps <- grps[map_lgl(grps, ~ !quo_is_null(.))]

  res <- df %>%
    group_by_at(grps) %>% 
    tally() %>% 
    ungroup()

  print(res)

  if (quo_is_null(enquo(group_var2))) {
    ggplot(aes(x=a, y=n), data = res)+
      geom_col()
  } else(
    ggplot(aes(x=a, y=n), data = res)+
      geom_col() +
      facet_grid(row= enquo(group_var2))
  )

}

根据 Matifo 的评论更新:

library(tidyverse)
library(rlang)
df <- tibble(a = sample(LETTERS[1:2], 100, replace = TRUE), 
             b = sample(LETTERS[3:4], 100, replace = TRUE), 
             value = rnorm(100,5,1))

f2 <- function(df, group_var1=a,  group_var2=NULL, group_var3) {

  grps <- enquos(a = group_var1, b = group_var2, c = group_var3, .ignore_empty = "all")
  grps <- grps[map_lgl(grps, ~ !quo_is_null(.))]

  res <- df %>%
    count(!!!grps) 

  print(res)

  ggplot(aes(x=a, y=n), data = res)+
    geom_col() +
    facet_grid(row= enquos(group_var2))
}

f2(df, group_var1 = a, group_var2=b)
#> # A tibble: 4 x 3
#>   a     b         n
#>   <chr> <chr> <int>
#> 1 A     C        29
#> 2 A     D        33
#> 3 B     C        18
#> 4 B     D        20

f2(df, group_var1 = a)
#> # A tibble: 2 x 2
#>   a         n
#>   <chr> <int>
#> 1 A        62
#> 2 B        38