r data.table

¿Cómo escribir una función que llama a una función que llama data.table?



(2)

Creo que podrías estar atándote en nudos. Esto funciona:

library(data.table) foo <- function(data, by){ by <- by data[, .N, by=by] } DT <- data.table(mtcars) foo(DT, ''gear'') plotfoo <- function(data, by){ foo(data, by) } plotfoo(DT, ''gear'')

Y ese método soporta pasar valores de caracteres:

> gg <- ''gear'' > plotfoo <- function(data, by){ + foo(data, by) + } > plotfoo(DT, gg) gear N 1: 4 12 2: 3 15 3: 5 5

El paquete data.table tiene una sintaxis especial que requiere que uno use expresiones como los argumentos i y j .

Esto tiene algunas implicaciones sobre cómo se escriben las funciones que aceptan y pasan argumentos a las tablas de datos, como se explica muy bien en la sección 1.16 de las Preguntas frecuentes .

Pero no puedo averiguar cómo tomar este nivel adicional.

Aquí hay un ejemplo. Digamos que quiero escribir una función de envoltorio foo() que hace un resumen específico de mis datos, y luego un segundo plotfoo() que llama a foo() y traza el resultado:

library(data.table) foo <- function(data, by){ by <- substitute(by) data[, .N, by=list(eval(by))] } DT <- data.table(mtcars) foo(DT, gear)

OK, esto funciona, porque obtengo mis resultados tabulados:

by N 1: 4 12 2: 3 15 3: 5 5

Ahora, trato de hacer lo mismo cuando escribo plotfoo() pero fallo miserablemente:

plotfoo <- function(data, by){ by <- substitute(by) foo(data, eval(by)) } plotfoo(DT, gear)

Pero esta vez me sale un mensaje de error:

Error: evaluation nested too deeply: infinite recursion / options(expressions=)?

OK, entonces la eval() está causando un problema. Vamos a quitarlo:

plotfoo <- function(data, by){ by <- substitute(by) foo(data, by) } plotfoo(DT, gear)

Oh no, me sale un nuevo mensaje de error:

Error in `[.data.table`(data, , .N, by = list(eval(by))) : column or expression 1 of ''by'' or ''keyby'' is type symbol. Do not quote column names. Useage: DT[,sum(colC),by=list(colA,month(colB))]

Y aquí es donde me quedo estancado.

Pregunta: ¿Cómo escribir una función que llame a una función que llame data.table?


Esto funcionará:

plotfoo <- function(data, by) { by <- substitute(by) do.call(foo, list(quote(data), by)) } plotfoo(DT, gear) # by N # 1: 4 12 # 2: 3 15 # 3: 5 5

Explicación:

El problema es que su llamada a foo() en plotfoo() parece a uno de los siguientes:

foo(data, eval(by)) foo(data, by)

Cuando foo procesa esas llamadas, substitute debidamente al segundo argumento formal ( by ) obteniendo como valor de s los símbolos eval(by) o by . Pero usted quiere que el valor de sea gear , como en la llamada foo(data, gear) .

do.call() resuelve este problema evaluando los elementos de su segundo argumento antes de construir la llamada que luego evalúa. Como resultado, cuando lo pasa, lo evalúa a su valor (el gear del símbolo) antes de construir una llamada que se vea (esencialmente) así:

foo(data, gear)