How do you code an R function so that it 'knows' to look in 'data' for the variables in other arguments?

If you run:

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

It runs, because lm knows to look in mtcars to find both mpg and cyl.

Yet mean(mpg) fails as it can't find mpg, so you do mean(mtcars$mpg) .

How do you code a function so that it knows to look in 'data' for the variables?

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

This will work with:

myfun(mtcars$mpg, mtcars$hp)

but will fail with:

myfun(mpg,hp, data=mtcars )

Cheers


Here's how I would code 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

If you're familiar with with() , it's interesting to see that it works in almost exactly the same way:

> with.default
# function (data, expr, ...) 
# eval(substitute(expr), data, enclos = parent.frame())
# <bytecode: 0x016c3914>
# <environment: namespace:base>

In both cases, the key idea is to first create an expression from the symbols passed in as arguments and then evaluate that expression using data as the 'environment' of the evaluation.

The first part (eg turning a + b into the expression mpg + hp ) is possible thanks to substitute() . The second part is possible because eval() was beautifully designed, such that it can take a data.frame as its evaluation environment.


lm "knows" to look in its data argument because it actually constructs a call to model.frame using its own call as the base. If you look at the code for lm , you'll see the necessary machinery in the first dozen lines or so.

You could replicate this for your own ends, but if your needs are simpler, you don't have to go to the same extent. For example:

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

Or, just look at evalq .


This is not exactly like what you asked for, but if you don't know about with() this might be an option:

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

You can remove the data argument to myfun for this.

链接地址: http://www.djcxy.com/p/4230.html

上一篇: 如何以指定的顺序连接字符串

下一篇: 你如何编写一个R函数,以便'知道'在其他参数中查找'数据'中的变量?