Как вы кодируете функцию R так, чтобы она "знала", чтобы искать "данные" для переменных в других аргументах?
Если вы запустите:
mod <- lm(mpg ~ factor(cyl), data=mtcars)
Он работает, потому что lm знает, как искать mtcars, чтобы найти mpg и cyl.
Тем не менее mean(mpg)
выходит из строя, так как он не может найти mpg, поэтому вы делаете mean(mtcars$mpg)
.
Как вы кодируете функцию, чтобы она знала, что нужно искать в "данных" для переменных?
myfun <- function (a,b,data){
return(a+b)
}
Это будет работать с:
myfun(mtcars$mpg, mtcars$hp)
но сбой:
myfun(mpg,hp, data=mtcars )
Приветствия
Ответы
Ответ 1
Вот как я бы закодировал 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
.
Ответ 2
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))
Вы можете удалить аргумент data
для myfun для этого.