Передача весов в glm () с помощью rlang - PullRequest
0 голосов
/ 27 января 2019

Я хочу передать 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().Мысли высоко ценятся.

1 Ответ

0 голосов
/ 31 января 2019

Проблема в том, что 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), ...) )
}
...