Jon*_*nas 14 r nse tidyeval rlang
我最近注意到这rlang::sym似乎不适用于匿名函数,我不明白为什么.这是一个例子,它非常笨拙和丑陋,但我认为它说明了这一点
require(tidyverse)
data <- tibble(x1 = letters[1:3],
x2 = letters[4:6],
val = 1:3)
get_it <- function(a, b){
data %>%
mutate(y1 = !!rlang::sym(a)) %>%
mutate(y2 = !!rlang::sym(b)) %>%
select(y1, y2, val)
}
get_it("x1", "x2")
Run Code Online (Sandbox Code Playgroud)
这定义了一些玩具数据和一个(可怕的)函数,它基本上根据列名重命名列.现在我可以为a和b的不同组合做同样的事情:
d <- tibble(x = c("x1", "x2"),
y = c("x2", "x1"))
d %>% mutate(tmp = map2(x, y, get_it))
Run Code Online (Sandbox Code Playgroud)
但是,如果我尝试使用匿名函数执行完全相同的操作,则它不起作用:
d %>% mutate(tmp = map2(x, y, function(a, b){
data %>%
mutate(y1 = !!rlang::sym(a)) %>%
mutate(y2 = !!rlang::sym(b)) %>%
select(y1, y2, val)
}))
Run Code Online (Sandbox Code Playgroud)
object 'a' not found即使函数完全相同,这也是失败的.有谁能解释为什么?
请注意,以下代码!!在匿名函数内部并按预期工作:
res1 <- d %>% mutate(tmp = map2(x, y, get_it))
Run Code Online (Sandbox Code Playgroud)
原始问题与unquoting运算符!!及其相对于非标准评估(NSE)函数内的匿名函数创建的优先级有关,例如select.考虑嵌套数据框架
res2 <- d %>% mutate(tmp = map2(x, y, function(a, b){
data %>%
mutate(y1 = eval(rlang::sym(a))) %>%
mutate(y2 = eval(rlang::sym(b))) %>%
select(y1, y2, val)
}))
identical(res1, res2) #TRUE
Run Code Online (Sandbox Code Playgroud)
如果我尝试使用选择每个内部数据框内的第一列
res1 <- d %>% mutate(tmp = map2(x, y, get_it))
Run Code Online (Sandbox Code Playgroud)
我得到一个mutate错误,因为在创建匿名函数(包含)的环境之前,!!相对于外部发生了取消引用.如果我移动匿名函数mutate()x1d
res2 <- d %>% mutate(tmp = map2(x, y, function(a, b){
data %>%
mutate(y1 = eval(rlang::sym(a))) %>%
mutate(y2 = eval(rlang::sym(b))) %>%
select(y1, y2, val)
}))
identical(res1, res2) #TRUE
Run Code Online (Sandbox Code Playgroud)
它可以正常工作,因为data遵循标准评估规则,现在在取消引用前创建匿名功能环境.
为帮助页面!!指出
!! 运营商无法引用其论点.它会在周围环境中立即进行评估.
这意味着当您编写复杂的NSE表达式(例如!!内部)时eval,取消引用将在表达式的整个环境中进行.正如@lionel在评论中指出的那样,NSE中的unquoting优先于其他事物,例如创建匿名函数环境.
| 归档时间: |
|
| 查看次数: |
761 次 |
| 最近记录: |