seleccionar - tablas en r
¿Cómo se codifica una función R para que ''sepa'' buscar en ''datos'' las variables en otros argumentos? (3)
Así es como codificaría 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
Si está familiarizado con with()
, es interesante ver que funciona casi exactamente de la misma manera:
> with.default
# function (data, expr, ...)
# eval(substitute(expr), data, enclos = parent.frame())
# <bytecode: 0x016c3914>
# <environment: namespace:base>
En ambos casos, la idea clave es crear primero una expresión a partir de los símbolos pasados como argumentos y luego evaluar esa expresión utilizando data
como el "entorno" de la evaluación.
La primera parte (por ejemplo, convertir a + b
en la expresión mpg + hp
) es posible gracias a substitute()
. La segunda parte es posible porque eval()
fue bellamente diseñado, de modo que puede tomar un data.frame
como su entorno de evaluación.
Si tu corres:
mod <- lm(mpg ~ factor(cyl), data=mtcars)
Se ejecuta, porque lm sabe buscar en mtcars para encontrar mpg y cyl.
Sin embargo, la mean(mpg)
falla porque no puede encontrar mpg, así que sí mean(mtcars$mpg)
.
¿Cómo se codifica una función para que sepa buscar las variables en ''datos''?
myfun <- function (a,b,data){
return(a+b)
}
Esto funcionará con:
myfun(mtcars$mpg, mtcars$hp)
pero fallará con:
myfun(mpg,hp, data=mtcars )
Aclamaciones
Esto no es exactamente como lo que pediste, pero si no conoces with()
esta podría ser una opción:
myfun <- function (a,b){
return(a+b)
}
with(mtcars, myfun(mpg, hp))
Puede eliminar el argumento de data
a myfun para esto.
lm
"sabe" que buscar en su argumento de data
porque en realidad construye una llamada a model.frame
usando su propia llamada como base. Si observa el código de lm
, verá la maquinaria necesaria en la primera docena de líneas aproximadamente.
Podría replicar esto para sus propios fines, pero si sus necesidades son más simples, no tiene que ir a la misma medida. Por ejemplo:
myfun <- function(..., data)
eval(match.call(expand.dots=FALSE)$...[[1]], data)
O simplemente mira evalq
.