如何编写一个R函数,使其“知道”在“data”中查找其他参数中的变量?

20

如果你运行:

mod <- lm(mpg ~ factor(cyl), data=mtcars)

lm知道在mtcars中查找mpg和cyl,所以代码可以运行。

然而, mean(mpg) 的执行会失败,因为它无法找到 mpg 变量,因此需要使用 mean(mtcars$mpg)

如何编写一个函数,使它知道在'data'中查找变量?

myfun <- function (a,b,data){
    return(a+b)
}

这将适用于:

myfun(mtcars$mpg, mtcars$hp)

但是会失败,错误信息为:

myfun(mpg,hp, data=mtcars )

干杯


2
我认为我还不够理解这个问题,无法发布简明扼要的答案,但是@Hadley在这里提供了非常详细的解释:https://github.com/hadley/devtools/wiki/Evaluation。 - Chase
谢谢,Chase。我知道可以问Hadley这个问题,因为ggplot是一组能够以这种方式工作的函数。现在我会去看一下。 - nzcoops
3个回答

20

这是我编写myfun()的代码:

myfun <- function(a, b, data) {
    eval(substitute(a + b), envir=data, enclos=parent.frame())
}

myfun(mpg, hp, mtcars)
#  [1] 131.0 131.0 115.8 131.4 193.7 123.1 259.3  86.4 117.8 142.2 140.8 196.4
# [13] 197.3 195.2 215.4 225.4 244.7  98.4  82.4  98.9 118.5 165.5 165.2 258.3
# [25] 194.2  93.3 117.0 143.4 279.8 194.7 350.0 130.4

如果你熟悉with(),那么有趣的是它几乎以完全相同的方式工作:

> with.default
# function (data, expr, ...) 
# eval(substitute(expr), data, enclos = parent.frame())
# <bytecode: 0x016c3914>
# <environment: namespace:base>
在这两种情况下,关键思路是先从传入的符号创建表达式,然后使用data作为评估的“环境”来评估该表达式。
第一部分(例如将a + b转换为表达式mpg + hp)得益于substitute()。第二部分之所以可能,是因为eval()被巧妙地设计成可以将data.frame作为其评估环境。

5

lm“知道”在其data参数中查找,因为它实际上使用自己的调用作为基础构造了一个对model.frame的调用。如果您查看lm的代码,您将在前十几行看到必要的机制。

您可以为自己的目的复制此操作,但如果您的需求更简单,则不必做到同样的程度。例如:

myfun <- function(..., data)
eval(match.call(expand.dots=FALSE)$...[[1]], data)

或者,只需查看evalq

3

这不完全符合您的要求,但如果您不了解with(),这可能是一种选择:

 myfun <- function (a,b){
    return(a+b)
 }
 with(mtcars, myfun(mpg, hp))

您可以删除myfun函数中的参数。

谢谢,我的意思并不是冒犯,但我更想让这个函数变得更好(为了用户的简便性),而不是使用一个变通方法。 - nzcoops

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接