Как вы кодируете функцию R, чтобы она «знала», как искать в «данных» переменные в других аргументах? - PullRequest
20 голосов
/ 13 декабря 2011

Если вы запустите:

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

Он запустится, потому что lm знает, что ищет в mtcars и mpg, и цил.mpg, так что вы делаете mean(mtcars$mpg).

Как вы кодируете функцию, чтобы она знала, что нужно искать переменные в «данных»?

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

Это будет работать с:

myfun(mtcars$mpg, mtcars$hp)

, но потерпит неудачу с:

myfun(mpg,hp, data=mtcars )

Приветствия

Ответы [ 3 ]

20 голосов
/ 13 декабря 2011

Вот как я бы кодировал 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 голосов
/ 13 декабря 2011

lm «знает» искать в своем аргументе data, потому что он фактически создает вызов model.frame, используя свой собственный вызов в качестве базы. Если вы посмотрите на код для lm, вы увидите необходимые машины в первых дюжинах строк или около того.

Вы можете повторить это для своих собственных целей, но если ваши потребности проще, вам не нужно идти в той же степени. Например:

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

Или просто посмотрите на evalq.

3 голосов
/ 13 декабря 2011

Это не совсем то, что вы просили, но если вы не знаете о with(), это может быть вариант:

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

Вы можете удалить аргумент data для myfun для этого.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...