scoping/non-standard R 函数中 glm 公式的评估问题
scoping/non-standard evaluation issue in glm's formula in a function in R
我有一个计算 table 和模型(以及更多...)的函数:
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
}
在公式中,我需要使用函数调用中提供的 x
和 y
(例如 x = DF1$x
和 y = DF1$y
)以及来自另一个数据框的变量(例如,来自 DF2
的 a
和 b
)。它因我的天真功能而失败:
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 搜索 x
和 y
?我想这个问题与非标准评估 and/or 范围界定有关,但我不知道如何解决它。
示例数据:
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))
为什么不把x
和y
加到函数的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
#
@DaveArmstrong 已经被接受的回答是正确的。这个答案解释了为什么原始版本的代码有错误。
@Thomas 在评论中引用文档说
If not found in data, the variables are taken from environment(formula), typically the environment from which glm is called.
“通常”这个词在这里很关键。确切的规则是,附加到公式的环境是首先计算公式表达式的环境,因为 ~
实际上是一个函数。它将评估环境附加到公式对象,当您传递对象时,它会一直伴随着它。
如果您 运行 glm(y ~ x)
,无论您在哪里调用,都会计算公式,因此这是“典型”情况。
在您的示例中,您在调用时创建了公式对象
fun(x = DF1$x,
y = DF1$y,
formula = y ~ x + a + b,
data = DF2)
这意味着全局环境(您进行此调用的地方)已附加到公式,但那里没有 y
,所以您得到了错误。
如果您通过调用
使用默认 formula = y ~ x
fun(x = DF1$x,
y = DF1$y,
data = DF2)
没有 formula
参数,它会起作用,因为默认参数是在使用它们的函数的评估框架中评估的。由于 fun()
具有由参数创建的局部变量 x
和 y
,那没问题。
您还问为什么 data = NULL
会在@DaveArmstrong 的函数中起作用。他使用
添加了 x
和 y
data$x <- x
data$y <- y
如果您从 data = NULL
开始,第一行将其更改为包含 x
的列表,第二行添加一个 y
组件,因此您最终得到一个包含的列表x
和 y
这对 glm()
中的 data
没问题。
我有一个计算 table 和模型(以及更多...)的函数:
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
}
在公式中,我需要使用函数调用中提供的 x
和 y
(例如 x = DF1$x
和 y = DF1$y
)以及来自另一个数据框的变量(例如,来自 DF2
的 a
和 b
)。它因我的天真功能而失败:
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 搜索 x
和 y
?我想这个问题与非标准评估 and/or 范围界定有关,但我不知道如何解决它。
示例数据:
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))
为什么不把x
和y
加到函数的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
#
@DaveArmstrong 已经被接受的回答是正确的。这个答案解释了为什么原始版本的代码有错误。
@Thomas 在评论中引用文档说
If not found in data, the variables are taken from environment(formula), typically the environment from which glm is called.
“通常”这个词在这里很关键。确切的规则是,附加到公式的环境是首先计算公式表达式的环境,因为 ~
实际上是一个函数。它将评估环境附加到公式对象,当您传递对象时,它会一直伴随着它。
如果您 运行 glm(y ~ x)
,无论您在哪里调用,都会计算公式,因此这是“典型”情况。
在您的示例中,您在调用时创建了公式对象
fun(x = DF1$x,
y = DF1$y,
formula = y ~ x + a + b,
data = DF2)
这意味着全局环境(您进行此调用的地方)已附加到公式,但那里没有 y
,所以您得到了错误。
如果您通过调用
使用默认formula = y ~ x
fun(x = DF1$x,
y = DF1$y,
data = DF2)
没有 formula
参数,它会起作用,因为默认参数是在使用它们的函数的评估框架中评估的。由于 fun()
具有由参数创建的局部变量 x
和 y
,那没问题。
您还问为什么 data = NULL
会在@DaveArmstrong 的函数中起作用。他使用
x
和 y
data$x <- x
data$y <- y
如果您从 data = NULL
开始,第一行将其更改为包含 x
的列表,第二行添加一个 y
组件,因此您最终得到一个包含的列表x
和 y
这对 glm()
中的 data
没问题。