R中函数的'glm()'公式中的作用域/非标准求值问题

vx6bjr1n  于 2023-03-20  发布在  其他
关注(0)|答案(2)|浏览(138)

我有一个计算表和模型的函数(以及更多...):

fun <- function(x, y, formula = y ~ x, data = NULL) {
  out <- list()
  out$tab <- table(x, y)
  out$mod <- glm(formula = formula,
                 family = binomial,
                 data = data)
  out

}
在公式中,我需要使用函数调用中提供的xy(例如x = DF1$xy = DF1$y)以及另一个 Dataframe 中的变量(例如DF2中的ab)。

fun(x = DF1$x,
    y = DF1$y,
    formula = y ~ x + a + b,
    data = DF2)
# Error in eval(predvars, data, env) : object 'y' not found

如何让glm()从函数环境中搜索xy?我想这个问题与非标准的求值和/或作用域有关,但我不知道如何修复它。
示例数据:

smp <- function(x = c(TRUE, FALSE),
                size = 1e2) {
  sample(x = x,
         size = size,
         replace = TRUE)
  }

DF1 <- data.frame(x = smp(),
                  y = smp())

DF2 <- data.frame(a = smp(x = LETTERS),
                  b = smp(x = LETTERS))
tv6aics1

tv6aics11#

为什么不在函数中将xy添加到data中呢?

fun <- function(x, y, formula = y ~ x, data = NULL) {
  if(length(x) != length(y) | 
     length(x) != nrow(data) | 
     length(y) != nrow(data))stop("x, y and data need to be the same length.\n")
  data$x <- x
  data$y <- y
  out <- list()
  out$tab <- table(x, y)
  out$mod <- glm(formula = formula,
                 family = binomial,
                 data = data)
  out
}

fun(x = DF1$x,
    y = DF1$y,
    formula = y ~ x + a + b,
    data = DF2)
# $tab
# y
# x       FALSE TRUE
# FALSE    27   29
# TRUE     21   23
# 
# $mod
# Call:  glm(formula = formula, family = binomial, data = data)
# 
# Coefficients:
#   (Intercept)        xTRUE           aB           aC           aD           aE           aF           aG           aH           aI           aJ  
# 3.2761      -1.8197       0.3409     -93.9103      -2.0697      20.6813     -41.5963      -1.1078      18.5921      -1.0857     -36.5442  
# aK           aL           aM           aN           aO           aP           aQ           aR           aS           aT           aU  
# -0.5730     -92.5513      -3.0672      22.8989     -53.6200      -0.9450       0.4626      -3.0672       0.3570     -22.8857       1.8867  
# aV           aW           aX           aY           aZ           bB           bC           bD           bE           bF           bG  
# 2.5307      19.5447     -90.5693    -134.0656      -2.5943      -1.2333      20.7726     110.6790      17.1022      -0.5279      -1.2537  
# bH           bI           bJ           bK           bL           bM           bN           bO           bP           bQ           bR  
# -21.7750     114.0199      20.3766     -42.5031      41.1757     -24.3553      -2.0310     -25.9223      -2.9145      51.2537      70.2707  
# bS           bT           bU           bV           bW           bX           bY           bZ  
# -4.7728      -3.7300      -2.0333      -0.3906      -0.5717      -4.0728       0.8155      -4.4021  
# 
# Degrees of Freedom: 99 Total (i.e. Null);  48 Residual
# Null Deviance:        138.5 
# Residual Deviance: 57.73  AIC: 161.7
# 
# Warning message:
#   glm.fit: fitted probabilities numerically 0 or 1 occurred 
#
r8xiu3jd

r8xiu3jd2#

@DaveArmstrong已经被接受的答案是正确的,这个答案解释了为什么原始版本的代码会出现错误。
@托马斯在评论中引用了这些医生的话
如果在数据中找不到变量,则从环境(公式)中获取变量,通常是从调用glm的环境中获取变量。
“通常”一词在这里很关键。确切的规则是,公式所附加的环境是公式表达式第一次求值的环境,因为~实际上是一个函数。它将求值环境附加到公式对象,并且当您传递对象时,求值环境始终与公式对象在一起。
如果运行glm(y ~ x),则无论在何处调用该函数,都会计算公式,因此这是“典型”情况。
在示例中,您在调用

fun(x = DF1$x,
y = DF1$y,
formula = y ~ x + a + b,
data = DF2)

这意味着全局环境(您进行此调用的位置)与公式关联,并且没有y,因此您得到了错误。
如果通过调用

fun(x = DF1$x,
y = DF1$y,
data = DF2)

如果没有formula参数,它也可以工作,因为默认参数是在使用它们的函数的求值框架中求值的,因为fun()有由参数创建的局部变量xy,这样就可以了。
您还问了为什么data = NULL可以在@DaveArmstrong的函数中工作,他使用

data$x <- x
data$y <- y

如果你从data = NULL开始,第一行把它变成一个包含x的列表,第二行添加一个y组件,所以你最终得到一个包含xy的列表,这对于glm()中的data来说是很好的。

相关问题