En R data.table, ¿cómo paso parámetros variables a una expresión?
-
12-12-2019 - |
Pregunta
Estoy atrapado con un pequeño problema con R data.table
.Su ayuda es muy apreciada.Cómo hago esto:
getResult <- function(dt, expr, gby) {
e <- substitute(expr)
b <- substitute(gby)
return(dt[,eval(e),by=b])
}
v1 <- "Sepal.Length"
v2 <- "Species"
dt <- data.table(iris)
rDT <- getResult(dt, sum(v1, na.rm=TRUE), v2)
Recibo el siguiente error:
Error en suma(v1, na.rm = VERDADERO):'Tipo' (personaje) inválido de argumento
Ahora, ambos v1
y v2
pasar de otro programa como variable de carácter, así que no puedo hacer esto v1<- quote(Sepal.Length)
lo que parece funcionar.
Solución
Una alternativa a la respuesta de flodel en los comentarios podría ser
e <- parse(text = paste0("sum(", v1, ", na.rm = TRUE)"))
b <- parse(text = v2)
rDT2 <- dt[, eval(e), by = eval(b)]
# b V1
# [1,] setosa 250.3
# [2,] versicolor 296.8
# [3,] virginica 329.4
EDITAR:
Y para poner esto en una función,
getResult <- function(dt, expr, gby){
return(dt[, eval(expr), by = eval(gby)])
}
(dtR <- getResult(dt = dt, expr = e, gby = b))
# gives the same result as above
EDITAR de Mateo:Hay una razón sutil por la cual el paste0
y eval
\ quote
Los métodos pueden ser más rápidos que get
en algunos casos también.Una de las razones por las que la agrupación puede ser rápida es que data.table
inspecciona j
para ver qué columnas utiliza, solo subconjuntos de las columnas utilizadas (Preguntas frecuentes 1.12 y 3.1).Usa base::all.vars(j)
Para hacer eso.Cuando usas get()
en j
la columna que se utiliza está oculta de all.vars
y data.table
recurre a subconjuntos de todas las columnas en caso de que j
la expresión los necesita (muy parecido a cuando el .SD
símbolo se utiliza en j
, para cual .SDcols
se agregó para resolver).Si todas las columnas se utilizan de todos modos, entonces no hay diferencia, pero si DT
es decir 1e7x100 entonces un agrupado j=sum(V1)
debería ser mucho más rápido que un grupo j=sum(get("V1"))
por esta razón.Al menos, eso es lo que se supone que debe suceder, y si no es así, puede ser un error.Si, por otro lado, muchas consultas se construyen dinámicamente y se repiten, entonces el tiempo para paste0
y parse
podría entrar en ello.Realmente todo depende.Configuración verbose=TRUE
debería imprimir un mensaje sobre qué columnas se han detectado como utilizadas por j
, para que se pueda comprobar.