Ha investigado brevemente, y parece un error data.table
.
> DT = data.table(a=1:1e6,b=1:1e6,c=1:1e6,d=1:1e6)
> Rprofmem()
> sapply(DT,class)
a b c d
"integer" "integer" "integer" "integer"
> Rprofmem(NULL)
> noquote(readLines("Rprofmem.out"))
[1] 4000040 :"as.list.data.table" "as.list" "lapply" "sapply"
[2] 4000040 :"as.list.data.table" "as.list" "lapply" "sapply"
[3] 4000040 :"as.list.data.table" "as.list" "lapply" "sapply"
[4] 4000040 :"as.list.data.table" "as.list" "lapply" "sapply"
> tracemem(DT)
> sapply(DT,class)
tracemem[000000000431A290 -> 00000000065D70D8]: as.list.data.table as.list lapply sapply
a b c d
"integer" "integer" "integer" "integer"
Así, mirando a as.list.data.table
:
> data.table:::as.list.data.table
function (x, ...)
{
ans <- unclass(x)
setattr(ans, "row.names", NULL)
setattr(ans, "sorted", NULL)
setattr(ans, ".internal.selfref", NULL)
ans
}
<environment: namespace:data.table>
>
Nota del unclass
molestos en la primera línea. ?unclass
confirma que se necesita una copia profunda de su argumento. De este vistazo rápido, no parece que sapply
o lapply
están haciendo la copia (no pensé que lo hicieran, ya que R es bueno para copiar y escribir, y no están escribiendo), sino más bien el as.list
en lapply
(que se distribuye al as.list.data.table
).
Por lo tanto, si evitamos el unclass
, debería acelerarse. Vamos a tratar:
> DT = data.table(a=1:1e7,b=1:1e7,c=1:1e7,d=1:1e7)
> system.time(sapply(DT,class))
user system elapsed
0.28 0.06 0.35
> system.time(sapply(DT,class)) # repeat timing a few times and take minimum
user system elapsed
0.17 0.00 0.17
> system.time(sapply(DT,class))
user system elapsed
0.13 0.04 0.18
> system.time(sapply(DT,class))
user system elapsed
0.14 0.03 0.17
> assignInNamespace("as.list.data.table",function(x)x,"data.table")
> data.table:::as.list.data.table
function(x)x
> system.time(sapply(DT,class))
user system elapsed
0 0 0
> system.time(sapply(DT,class))
user system elapsed
0.01 0.00 0.02
> system.time(sapply(DT,class))
user system elapsed
0 0 0
> sapply(DT,class)
a b c d
"integer" "integer" "integer" "integer"
>
Así que, sí, infinitamente mejor.
He criado bug report #2000 para eliminar el método as.list.data.table
, ya que un data.table
is()
ya un list
, también. Esto podría acelerar un buen número de modismos, como lapply(.SD,...)
. [EDITAR: Esto fue arreglado en v1.8.1].
Gracias por preguntar esta pregunta !!
No estoy seguro de que lo siga. ¿Por qué no simplemente 'sapply (DT, clase)'? –
sincronizaciones agregadas en el texto anterior –
@MatthewDowle: Creo que el OP significa que crea samente las variables temporales con los subconjuntos de data.table para pasar a FUN para cada columna. Dado que data.table es realmente grande y tiene muchas columnas, no es eficiente. Por esta razón, su solución consiste en reducir primero la tabla de datos a una fila, luego llamar sapply ... – digEmAll