rlang:Curly 卷曲运算符和 RHS 上字符串内的隧道数据变量

rlang: Curly curly operator and tunneling data-variables inside strings on RHS

我觉得curly curly是bang bang很好的接班人。尽管如此,我仍然在努力理解 tidyverse NSE。

假设我想创建一个在数据帧上运行的简单函数,获取多列,以长格式重塑它们,并从重塑后的列中提取因子。我还希望能够定义因子水平,或者默认情况下按照所选列在重塑过程之前的顺序保留它们。

我用 bang bang 和 curly 写了同样的函数。

library(tidyverse)

df_test <- data.frame(
  id = c("id1", "id2"),
  item1 = c(0, 4),
  item2 = c(3, 2),
  item3 = c(1, 4),
  item4 = c(3, 4),
  item5 = c(1, NA)
)

# Bang bang way
vars_factor_to_long <- function(data, vars) {                     
  vars_enq <- rlang::enquo(vars)
  vars_name <- unname(tidyselect::vars_select(unique(names(data)), !!vars_enq))
  data <-
    data %>%
    tidyr::pivot_longer(cols = !!vars_enq, names_to = "item", values_to = "value") %>%
    dplyr::mutate(item = factor(item, levels = vars_name)) 
  data
}

vars_factor_to_long(df_test, item1:item5)
#> # A tibble: 10 x 3
#>    id    item  value
#>    <fct> <fct> <dbl>
#>  1 id1   item1     0
#>  2 id1   item2     3
#>  3 id1   item3     1
#>  4 id1   item4     3
#>  5 id1   item5     1
#>  6 id2   item1     4
#>  7 id2   item2     2
#>  8 id2   item3     4
#>  9 id2   item4     4
#> 10 id2   item5    NA

# Curly curly way works the same, but doesn't need the enquo
vars_factor_to_long2 <- function(data, vars) {                     
  vars_name <- unname(tidyselect::vars_select(unique(names(data)), {{vars}}))
  data <-
    data %>%
    tidyr::pivot_longer(cols = {{vars}}, names_to = "item", values_to = "value") %>%
    dplyr::mutate(item = factor(item, levels = vars_name))
    data
}

vars_factor_to_long2(df_test, item1:item5)
#> # A tibble: 10 x 3
#>    id    item  value
#>    <fct> <fct> <dbl>
#>  1 id1   item1     0
#>  2 id1   item2     3
#>  3 id1   item3     1
#>  4 id1   item4     3
#>  5 id1   item5     1
#>  6 id2   item1     4
#>  7 id2   item2     2
#>  8 id2   item3     4
#>  9 id2   item4     4
#> 10 id2   item5    NA

reprex package (v0.3.0)

于 2021-02-05 创建

这很好用,但我发现数据变量可以通过使用类似于 glue 的语法在带有 curly curly 的字符串中隧道化。例如:

# Curly curly - tunneling data-variable inside strings with glue-like syntax
mean_by <- function(data, by, vars) {
  data %>%
    group_by({{ by }}) %>%
    summarise("{{ vars }}" := mean({{ vars }}, na.rm = TRUE))
}

mean_by(df_test, id, item1)
#> # A tibble: 2 x 2
#>   id    item1
#>   <fct> <dbl>
#> 1 id1       0
#> 2 id2       4
mean_by(df_test, id, item1:item2)
#> # A tibble: 2 x 2
#>   id    `item1:item2`
#>   <fct>         <dbl>
#> 1 id1             1.5
#> 2 id2             3

reprex package (v0.3.0)

于 2021-02-05 创建

有没有一种方法可以将数据变量名称(如第二个示例)用作第一个示例函数中的因子级别?我怀疑如果提供了多个列,这种隧道会出现问题,但是,我怎样才能将至少一个列名称隧道到 RHS?

关于这个新的 rlang 主题的任何讨论都将帮助我了解更多。 谢谢。

无论如何你都需要对用户选择进行隧道化然后获取名称,所以我认为你的方法很好。我会通过使用 dplyr 而不是低级 tidyselect 来简化它:

vars_factor_to_long2 <- function(data, vars) {
  vars <- names(dplyr::select(data, {{ vars }}))

  data %>%
    tidyr::pivot_longer(
      cols = all_of(vars),
      names_to = "item",
      values_to = "value"
    ) %>%
    dplyr::mutate(
      item = factor(item, levels = vars)
    )
}