我正在开发一个包含对lm()
的调用的自定义函数,但由于某种原因,该函数失败了。我无法理解它失败的原因。
考虑将此示例简化为简单:
myfun <- function(form., data., subs., ...){
lm(form., data., subs., ...)
}
这将导致错误:
myfun(mpg ~ cyl + hp, mtcars, TRUE)
## Error in eval(expr, envir, enclos) : object 'subs.' not found
但是直接使用lm()
可以正常工作:
lm(mpg ~ cyl + hp, mtcars, TRUE)
##
## Call:
## lm(formula = mpg ~ cyl + hp, data = mtcars, subset = TRUE)
##
## Coefficients:
## (Intercept) cyl hp
## 36.90833 -2.26469 -0.01912
我试过调试,但仍然无法解决问题的根源。为什么自定义功能失败?显然subs.
已经提供给函数...
虽然下面提出的大多数解决方案都有助于这个简单的情况,但如果我添加一个简单的扭曲,该功能仍将失败。例如,expand.model.frame()
依赖于公式的环境,但如果我使用正常的评估解决方案则会失败:
myfun <- function(form., data., subs., ...){
fit <- lm(form., data.[ subs., ], ...)
expand.model.frame(fit, ~ drat)
}
myfun(mpg ~ cyl + hp, mtcars, TRUE)
## Error in eval(expr, envir, enclos) : object 'data.' not found
这显然与原始问题有关,但我无法弄清楚如何。模型公式的环境是否以某种方式被破坏了?
答案 0 :(得分:5)
正如评论中所建议的,另一种解决方案是在非交互式使用中完全避免subset
参数,而是使用标准评估:
myfun <- function(form., data., subs., ...){
lm(form., data.[ subs., ], ...)
}
现在这可以按预期工作:
myfun(formula(mpg ~ cyl + hp), mtcars, TRUE)
但是,如果您的自定义函数随后包含expand.model.frame()
或类似的调用,这似乎本身对subset
参数的非标准评估很敏感,那么这仍然不够。为了使函数健壮并避免意外,您需要(1)在自定义函数中定义公式(另请参阅reformulate
approach)和(2)将数据之前子集到lm()
在显着避免subset
参数时调用。
像这样:
myfun <- function(form., data., subs., ...){
stopifnot(is.character(form.))
data. <- data.[ subs., ]
fit <- lm(as.formula(form.), data., ...)
expand.model.frame(fit, ~ drat)
}
myfun("mpg ~ cyl + hp", mtcars, TRUE)
我尝试使用(1)或(2),但仍设法从某些函数中遇到奇怪的错误,而且只有(1)和(2)这两个错误似乎已经消失了远...
答案 1 :(得分:4)
此函数不起作用的原因是因为评估参数subset
的方式:
所有'权重','子集'和'偏移'都在相同的情况下进行评估 作为'公式'中的变量的方式,首先是'数据',然后是' '公式'的环境。
换句话说,lm
在subs.
中查找名为data
的变量,然后在formula
的环境中查找,因为没有subs.
在这两种环境中的变量都会产生错误。
答案 2 :(得分:3)
您可以这样做:
myfun <- function(form., data., subs., ...){
lm(as.formula(form.), data., subs., ...)
}
将其称为myfun("mpg ~ cyl + hp", mtcars, T)
。这会强制在函数myfun
的环境中创建公式,然后该函数将包含subs.
。
答案 3 :(得分:3)
根据@ErnestA的答案,您可以修改您的功能,以确保公式subs.
的环境中存在form.
:
myfun <- function(form., data., subs., ...){
assign("subs.", subs., envir=environment(form.))
lm(form., data., subs., ...)
}
ETA避免污染form
的环境,因此可以创建一个新的环境:
myfun <- function(form., data., subs., ...){
environment(form.) <- new.env(parent=environment(form.))
assign("subs.", subs., envir=environment(form.))
lm(form., data., subs., ...)
}
ETA也许唯一解决lm问题的方法是将form.
的环境设置为myfun
的环境:
myfun <- function(form., data., subs., ...){
environment(form.) <- environment()
lm(form., data., subs., ...)
}
myfun(mpg ~ cyl + hp, mtcars, TRUE)
## Call:
## lm(formula = form., data = data., subset = subs.)
##
## Coefficients:
## (Intercept) cyl hp
## 36.90833 -2.26469 -0.01912
转到expand.model.frame
问题,找不到subs.
,尽管它位于使用?expand.model.frame
所述的环境中。这是expand.model.frame中的错误吗?或至少与文档冲突?
myfun <- function(form., data., subs., ...){
environment(form.) <- environment()
fit <- lm(form., data., subs., ...)
print(ls(environment(formula(fit))))
expand.model.frame(fit, ~drat )
}
myfun(mpg ~ cyl + hp, mtcars, TRUE)
## [1] "data." "fit" "form." "subs."
## Error in eval(expr, envir, enclos) : object 'subs.' not found
将subs.
放入父环境似乎有效。
myfun <- function(form., data., subs., ...){
environment(form.) <- environment()
fit <- lm(form., data., subs., ...)
assign("subs.", subs., envir = parent.env(environment(formula(fit))))
expand.model.frame(fit, ~drat)
}
myfun(mpg ~ cyl + hp, mtcars, TRUE)
## mpg cyl hp drat
## Mazda RX4 21.0 6 110 3.90
## Mazda RX4 Wag 21.0 6 110 3.90
## Datsun 710 22.8 4 93 3.85
## Hornet 4 Drive 21.4 6 110 3.08
## etc.
但这会导致污染父环境的问题,在这种情况下R_GlobalEnv
。我无法使用除R_GlobalEnv
之外的任何其他内容作为父级。