gpt4 book ai didi

r - 为什么是enquo + !!最好替代+评估

转载 作者:行者123 更新时间:2023-12-03 10:28:52 25 4
gpt4 key购买 nike

在以下示例中,为什么我们比f1更喜欢使用f2?从某种意义上说它更有效率吗?对于以前以R为基础的用户,使用“替换+评估”选项似乎更为自然。

library(dplyr)

d = data.frame(x = 1:5,
y = rnorm(5))

# using enquo + !!
f1 = function(mydata, myvar) {
m = enquo(myvar)
mydata %>%
mutate(two_y = 2 * !!m)
}

# using substitute + eval
f2 = function(mydata, myvar) {
m = substitute(myvar)
mydata %>%
mutate(two_y = 2 * eval(m))
}

all.equal(d %>% f1(y), d %>% f2(y)) # TRUE

换句话说,除了这个特定的示例之外,我的问题是:我可以摆脱使用具有良好基础R的 dplyr NSE函数进行编程的麻烦,例如replace + eval,还是真的需要学习爱上所有这些 rlang函数,因为它有好处吗(速度,清晰度,组成性...)?

最佳答案

我想给出一个独立于dplyr的答案,因为与enquo相比,使用substitute有一个非常明显的优势。两者都在函数的调用环境中进行查找,以识别提供给该函数的表达式。区别在于substitute()仅执行一次,而!!enquo()将正确遍历整个调用堆栈。

考虑一个使用substitute()的简单函数:

f <- function( myExpr ) {
eval( substitute(myExpr), list(a=2, b=3) )
}

f(a+b) # 5
f(a*b) # 6

当调用嵌套在另一个函数中时,此功能将中断:
g <- function( myExpr ) {
val <- f( substitute(myExpr) )
## Do some stuff
val
}

g(a+b)
# myExpr <-- OOPS

现在考虑使用 enquo()重写的相同函数:
library( rlang )

f2 <- function( myExpr ) {
eval_tidy( enquo(myExpr), list(a=2, b=3) )
}

g2 <- function( myExpr ) {
val <- f2( !!enquo(myExpr) )
val
}

g2( a+b ) # 5
g2( b/a ) # 1.5

这就是为什么 enquo() + !!优于 substitute() + eval()的原因。 dplyr只是简单地充分利用此属性来构建一组连贯的NSE函数。

更新: rlang 0.4.0引入了一个新的运算符 {{(发音为“curly curl”),实际上是 !!enquo()的简写形式。这使我们可以将 g2的定义简化为
g2 <- function( myExpr ) {
val <- f2( {{myExpr}} )
val
}

关于r - 为什么是enquo + !!最好替代+评估,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49700912/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com