Convertir un marco de datos en una tabla de datos sin copiar


81

Tengo un marco de datos grande (del orden de varios GB) que me gustaría convertir a data.table. El uso as.data.tablecrea una copia del marco de datos, lo que significa que necesito que la memoria disponible sea al menos el doble del tamaño de los datos. ¿Hay alguna forma de realizar la conversión sin una copia?

Aquí hay un ejemplo simple para demostrar:

library(data.table)
N <- 1e6
K <- 1e2
data <- as.data.frame(rep(data.frame(rnorm(N)), K))

gc(reset=TRUE)
tracemem(data)
data <- as.data.table(data)
gc()

Con salida:

library(data.table)
# data.table 1.8.10  For help type: help("data.table")
N <- 1e6
K <- 1e2
data <- as.data.frame(rep(data.frame(rnorm(N)), K))

gc(reset=TRUE)
# used  (Mb) gc trigger   (Mb)  max used  (Mb)
# Ncells    303759  16.3     597831   32.0    303759  16.3
# Vcells 100442572 766.4  402928632 3074.2 100442572 766.4
tracemem(data)
# [1] "<0x363fda0>"
data <- as.data.table(data)
# tracemem[0x363fda0 -> 0x31e4260]: copy as.data.table.data.frame as.data.table 
gc()
# used  (Mb) gc trigger   (Mb)  max used   (Mb)
# Ncells    304519  16.3     597831   32.0    306162   16.4
# Vcells 100444242 766.4  322342905 2459.3 200933219 1533.0

Respuestas:


92

Está disponible a partir de la v1.9.0 + . De NEWS :

o Después de esta publicación SO , setDTahora se implementa una función que toma un list(con nombre y / o sin nombre), data.frame(o data.table) como entrada y devuelve el mismo objeto como data.table por referencia (sin ninguna copia). Vea ?setDTejemplos para más.

Esto está de acuerdo con la data.tableconvención de nomenclatura: todas las set*funciones se modifican por referencia. :=es el único otro que también modifica por referencia.

require(data.table) # v1.9.0+
setDT(data) # converts data which is a data.frame to data.table *by reference*

Consulte el historial para obtener respuestas más antiguas (ahora desactualizadas).


@Arun: Gracias por una respuesta detallada. De hecho, estaba preguntando cómo convertir un marco de datos en un data.table, pero fui descuidado al crear el ejemplo del juguete, actualizaré mi pregunta para convertirlo en un marco de datos. ¿Funcionará entonces la misma idea para un marco de datos, por ejemplo, deshacerse de los dos primeros setattr ya que un marco de datos ya los tiene y mantener el resto?
ytsaig

@YT, si te refieres a obtener un "data.frame" en un "data.table", entonces, por supuesto, lo que dices es correcto. Si te refieres a la lista de data.frames, tendrás que vincularlos (columna o fila) antes para establecer la clase y asignar.
Arun

@Arun, me refería al primero, un solo marco de datos a un data.table, edité la pregunta para reflejarla mejor. Gracias nuevamente por una solución inteligente. Puedo aceptar la respuesta tal cual o esperar si desea editarla para que coincida con la pregunta revisada.
ytsaig

2
Quizás esta publicación de Matthew ayude a arrojar más luz truelength.
Arun

3
@eddi Antes de R2.14.0, el truelengthmiembro del encabezado vectorial de R no fue inicializado por R. En C, si no inicializa una variable, tiene contenido indefinido (lo que sea que esté en ese trozo de RAM anteriormente). data.table()y creadores similares se inicializan truelengthen 0 antes de solicitar alloc.colcompatibilidad con versiones anteriores a R 2.14.0. alloc.colse ve truelengthcomo una entrada (0 se toma para significar longitud verdadera == longitud). En un momento pensé que data.table tendría que depender de R> = 2.14.0 debido a esto, pero logré mantenerlo R> = 2.12.0. Pruebo con R2.12.0 antes de cada lanzamiento a CRAN.
Matt Dowle
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.