我想通过一个函数将weights
传递给glm()
,而不必使用eval(substitute())
或do.call()
方法,而是使用rlang
。
这描述了更复杂的基础功能。
# 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)
(要突出显示提示)。
我知道这里的weights参数是错误的,我尝试了许多不成功的方法来完成这些任务。实际函数将传递给purrr:map()
或purrr:invoke()
的版本,这就是为什么我要避免使用简单的do.call()
的原因。思想大加赞赏。
答案 0 :(得分:2)
问题是glm()
可以识别为其weights
参数提供的表达式,但不支持准引号,因为它使用基数quote()
/ substitute()
/ eval()
机制代替rlang
。 This causes problems for nested expression arithmetic。
解决这个问题的一种方法是组成整个glm
表达式,然后对其求值。可以使用...
来提供可选参数。
myglm2 <- function( .data, y, x, weights, ... ) {
myglm <- expr( glm(!!enexpr(y) ~ !!enexpr(x), data=.data,
weights = !!enexpr(weights), ...) )
eval(myglm)
}
myglm2(mydata, outcome, group)
# Call: glm(formula = outcome ~ group, data = .data)
myglm2(mydata, outcome, group, wgts)
# Call: glm(formula = outcome ~ group, data = .data, weights = wgts)
myglm2(mydata, outcome, group, wgts, subset=7:10)
# Call: glm(formula = outcome ~ group, data = .data, weights = wgts,
# subset = ..1)
# While masked as ..1, the 7:10 is nevertheless correctly passed to glm()
要遵循@lionel的建议,您可以将表达式组成/求值封装到一个独立的函数中:
value <- function( e ) {eval(enexpr(e), caller_env())}
myglm2 <- function( .data, y, x, weights, ... ) {
value( glm(!!enexpr(y) ~ !!enexpr(x), data=.data,
weights = !!enexpr(weights), ...) )
}