使用 dplyr 编程时 ensym 和 enquo 有什么区别?
What is the difference between ensym and enquo when programming with dplyr?
对 tidy evaluation 比较陌生,虽然我正在使用这些函数,但我想知道为什么使用不同的辅助函数。例如,enquo
和 ensym
有什么区别?在我下面制作的捕捉每日平均线和移动平均线的函数中,它们是可以互换的:
library(dplyr)
library(lubridate)
library(rlang)
library(zoo)
manipulate_for_ma <- function(data, group_var, da_col_name, summary_var, ma_col_name) {
group_var <- ensym(group_var)
summary_var <- enquo(summary_var)
da_col_name <- ensym(da_col_name)
ma_col_name <- enquo(ma_col_name)
data %>%
group_by(!!group_var) %>%
summarise(!!da_col_name := mean(!!summary_var, na.rm = TRUE)) %>%
mutate(!!ma_col_name := rollapply(!!da_col_name,
30,
mean,
na.rm = TRUE,
partial = TRUE,
fill = NA)) %>%
rename(date = !!group_var)
}
lakers %>%
mutate(date = ymd(date)) %>%
manipulate_for_ma(group_var = date,
da_col_name = points_per_play_da,
summary_var = points,
points_per_play_ma)
# A tibble: 78 x 3
date points_per_play_da points_per_play_ma
<date> <dbl> <dbl>
1 2008-10-28 0.413 0.458
2 2008-10-29 0.431 0.459
3 2008-11-01 0.408 0.456
4 2008-11-05 0.386 0.457
我读过 enquo
here and ensym
(here)[https://adv-r.hadley.nz/quasiquotation.html]。 ensym
的区别是限制性更强,只接受字符串或类似字符串的对象吗?
这里有一个例子说明了一个区别(即 enquo
捕获调用环境而 ensym
不捕获)。希望它不言自明:
library(rlang)
f <- function(x) {
foo <- 42
print(eval_tidy(quo(!! ensym(x))))
print(eval_tidy(quo(!! enquo(x))))
}
foo <- 3
f(foo)
# [1] 42
# [1] 3
或者稍微复杂一点的:
library(rlang)
myenv <- new.env()
local(envir = myenv, {
foo <- 17
g <- function(x) {
print(eval_tidy(quo(!! ensym(x))))
print(eval_tidy(quo(!! enquo(x))))
}
})
foo <- 123
myenv$g(foo)
#> [1] 17
#> [1] 123
由 reprex package (v0.3.0)
于 2019-09-18 创建
使用 dplyr 时,差异通常不明显,因为它足够简单,总是首先在 .data
参数的上下文中查找名称。
另一个镜头:
library(rlang)
library(dplyr, warn.conflicts = FALSE)
test <- function(x){
Species <- "bar"
cat("--- enquo builds a quosure from any expression\n")
print(enquo(x))
cat("--- ensym captures a symbol or a literal string as a symbol\n")
print(ensym(x))
cat("--- evaltidy will evaluate the quosure in its environment\n")
print(eval_tidy(enquo(x)))
cat("--- evaltidy will evaluate a symbol locally\n")
print(eval_tidy(ensym(x)))
cat("--- but both work fine where the environment doesn't matter\n")
identical(select(iris,!!ensym(x)), select(iris,!!enquo(x)))
}
Species = "foo"
test(Species)
#> --- enquo builds a quosure from any expression
#> <quosure>
#> expr: ^Species
#> env: global
#> --- ensym captures a symbol or a literal string as a symbol
#> Species
#> --- evaltidy will evaluate the quosure in its environment
#> [1] "foo"
#> --- evaltidy will evaluate a symbol locally
#> [1] "bar"
#> --- but both work fine where the environment doesn't matter
#> [1] TRUE
test("Species")
#> --- enquo builds a quosure from any expression
#> <quosure>
#> expr: ^"Species"
#> env: empty
#> --- ensym captures a symbol or a literal string as a symbol
#> Species
#> --- evaltidy will evaluate the quosure in its environment
#> [1] "Species"
#> --- evaltidy will evaluate a symbol locally
#> [1] "bar"
#> --- but both work fine where the environment doesn't matter
#> [1] TRUE
test(paste0("Spec","ies"))
#> --- enquo builds a quosure from any expression
#> <quosure>
#> expr: ^paste0("Spec", "ies")
#> env: global
#> --- ensym captures a symbol or a literal string as a symbol
#> Only strings can be converted to symbols
由 reprex package (v0.3.0)
于 2019-09-23 创建
对 tidy evaluation 比较陌生,虽然我正在使用这些函数,但我想知道为什么使用不同的辅助函数。例如,enquo
和 ensym
有什么区别?在我下面制作的捕捉每日平均线和移动平均线的函数中,它们是可以互换的:
library(dplyr)
library(lubridate)
library(rlang)
library(zoo)
manipulate_for_ma <- function(data, group_var, da_col_name, summary_var, ma_col_name) {
group_var <- ensym(group_var)
summary_var <- enquo(summary_var)
da_col_name <- ensym(da_col_name)
ma_col_name <- enquo(ma_col_name)
data %>%
group_by(!!group_var) %>%
summarise(!!da_col_name := mean(!!summary_var, na.rm = TRUE)) %>%
mutate(!!ma_col_name := rollapply(!!da_col_name,
30,
mean,
na.rm = TRUE,
partial = TRUE,
fill = NA)) %>%
rename(date = !!group_var)
}
lakers %>%
mutate(date = ymd(date)) %>%
manipulate_for_ma(group_var = date,
da_col_name = points_per_play_da,
summary_var = points,
points_per_play_ma)
# A tibble: 78 x 3
date points_per_play_da points_per_play_ma
<date> <dbl> <dbl>
1 2008-10-28 0.413 0.458
2 2008-10-29 0.431 0.459
3 2008-11-01 0.408 0.456
4 2008-11-05 0.386 0.457
我读过 enquo
here and ensym
(here)[https://adv-r.hadley.nz/quasiquotation.html]。 ensym
的区别是限制性更强,只接受字符串或类似字符串的对象吗?
这里有一个例子说明了一个区别(即 enquo
捕获调用环境而 ensym
不捕获)。希望它不言自明:
library(rlang)
f <- function(x) {
foo <- 42
print(eval_tidy(quo(!! ensym(x))))
print(eval_tidy(quo(!! enquo(x))))
}
foo <- 3
f(foo)
# [1] 42
# [1] 3
或者稍微复杂一点的:
library(rlang)
myenv <- new.env()
local(envir = myenv, {
foo <- 17
g <- function(x) {
print(eval_tidy(quo(!! ensym(x))))
print(eval_tidy(quo(!! enquo(x))))
}
})
foo <- 123
myenv$g(foo)
#> [1] 17
#> [1] 123
由 reprex package (v0.3.0)
于 2019-09-18 创建使用 dplyr 时,差异通常不明显,因为它足够简单,总是首先在 .data
参数的上下文中查找名称。
另一个镜头:
library(rlang)
library(dplyr, warn.conflicts = FALSE)
test <- function(x){
Species <- "bar"
cat("--- enquo builds a quosure from any expression\n")
print(enquo(x))
cat("--- ensym captures a symbol or a literal string as a symbol\n")
print(ensym(x))
cat("--- evaltidy will evaluate the quosure in its environment\n")
print(eval_tidy(enquo(x)))
cat("--- evaltidy will evaluate a symbol locally\n")
print(eval_tidy(ensym(x)))
cat("--- but both work fine where the environment doesn't matter\n")
identical(select(iris,!!ensym(x)), select(iris,!!enquo(x)))
}
Species = "foo"
test(Species)
#> --- enquo builds a quosure from any expression
#> <quosure>
#> expr: ^Species
#> env: global
#> --- ensym captures a symbol or a literal string as a symbol
#> Species
#> --- evaltidy will evaluate the quosure in its environment
#> [1] "foo"
#> --- evaltidy will evaluate a symbol locally
#> [1] "bar"
#> --- but both work fine where the environment doesn't matter
#> [1] TRUE
test("Species")
#> --- enquo builds a quosure from any expression
#> <quosure>
#> expr: ^"Species"
#> env: empty
#> --- ensym captures a symbol or a literal string as a symbol
#> Species
#> --- evaltidy will evaluate the quosure in its environment
#> [1] "Species"
#> --- evaltidy will evaluate a symbol locally
#> [1] "bar"
#> --- but both work fine where the environment doesn't matter
#> [1] TRUE
test(paste0("Spec","ies"))
#> --- enquo builds a quosure from any expression
#> <quosure>
#> expr: ^paste0("Spec", "ies")
#> env: global
#> --- ensym captures a symbol or a literal string as a symbol
#> Only strings can be converted to symbols
由 reprex package (v0.3.0)
于 2019-09-23 创建