使用 rlang 将权重传递给 glm()

Passing weights to glm() using rlang

我想通过函数将 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)

(刻度为高亮)。

我知道这里的权重参数是错误的,我尝试了很多不同的方法都没有成功。实际功能将传递给 purrr:map()purrr:invoke() 的版本,这就是为什么我想避免简单的 do.call()。思想非常感激。

问题是 glm() 可以识别提供给其 weights 参数的表达式,但不支持准引号,因为它使用基数 quote() / substitute() / eval() 机制而不是 rlang.

绕过它的一种方法是组合整个 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), ...) )
}