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

时间:2019-01-26 22:30:48

标签: r glm rlang tidyeval

我想通过一个函数将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()的原因。思想大加赞赏。

1 个答案:

答案 0 :(得分:2)

问题是glm()可以识别为其weights参数提供的表达式,但不支持准引号,因为它使用基数quote() / substitute() / eval()机制代替rlangThis 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), ...) )
}