我希望通过使用rlang
,将weights
传递给glm()
函数,而无需使用eval(substitute())
或do.call()
方法,并使其易于理解。
这描述了一个更复杂的基础函数。
# Toy data
mydata = dplyr::tibble(outcome = c(0,0,0,0,0,0,0,0,1,1,1,1,1,1),
group = c(0,1,0,1,0,1,0,1,0,1,0,1,0,1),
wgts = c(1,1,1,1,1,1,1,1,1,1,1,1,1,1)
)
# This works
glm(outcome ~ group, data = mydata)
# This works
glm(outcome ~ group, data = mydata, weights = wgts)
library(rlang)
# Function not passing weights
myglm <- function(.data, y, x){
glm(expr(!! enexpr(y) ~ !! enexpr(x)), data = .data)
}
# This works
myglm(mydata, outcome, group)
# Function passing weights
myglm2 <- function(.data, y, x, weights){
glm(expr(!! enexpr(y) ~ !! enexpr(x)), `weights = !! enexpr(weights)`, data = .data)
}
# This doesn't work
myglm2(mydata, outcome, group, wgts)
(Ticks are to highlight)。
我知道这里的weights参数是错误的,我尝试了许多不同的方法,但都没有成功。实际函数将传递给purrr:map()
或purrr:invoke()
版本,这就是为什么我想避免简单的do.call()
。非常感谢您的想法。
expr + eval
的内容提取到一个函数中(例如value <- function(expr) eval(enexpr(expr))
)。然后你可以使用value(glm(!!enexpr(y) ~ !!enexpr(x))
,这样会更好一些。不需要使用eval_tidy()
,因为glm()
无法很好地处理 quosures。 - Lionel Henryfunction(e) {eval(enexpr(e))}
给了我一个cannot coerce class ‘"rlang_fake_data_pronoun"’ to a data.frame
的错误。我通过使用eval_tidy(enquo(e))
来解决这个问题。 - Artem Sokolov!!!enexprs(...)
。将捕获到的点拼接到裸表达式中比拼接到quo引用中更糟糕,因为你会失去正确的环境。如果直接传递这些点,看起来更整洁,而且更健壮和准确。 - Lionel Henryvalue <- function(e) eval(enexpr(e), caller_env())
。至于enexprs()
,这种方式传递点仍然不是一个好主意,在许多情况下,你会得到一个错误的函数。我会在myglm2()
中添加一个weights
参数,并在glm()
调用中引用/取消引用它。然后正常传递点。 - Lionel Henry