Как вы кодируете функцию 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 )

ура

3 ответа

Решение

Вот как я бы код 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 как его среда оценки.

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

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

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

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

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

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

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

Другие вопросы по тегам