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)
)
}
我觉得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)
)
}