84 votes

Convertir un cadre de données en tableau de données sans copie

J'ai un grand cadre de données (de l'ordre de plusieurs Go) que j'aimerais convertir en un fichier de type data.table . Utilisation de as.data.table crée une copie du cadre de données, ce qui signifie que la mémoire disponible doit être au moins deux fois plus grande que la taille des données. Existe-t-il un moyen d'effectuer la conversion sans copie ?

Voici un exemple simple pour le démontrer :

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()

Avec sortie :

> 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

95voto

Arun Points 41689

Mise à jour : Ceci est maintenant implémenté dans v1.8.11 . De NOUVELLES :

o Suivi ce poste de S.O. une fonction setDT est maintenant implémenté et prend un list (nommés et/ou non nommés), data.frame (ou data.table ) en entrée et renvoie le même objet en tant que data.table par référence (sans aucune copie). Il a également un argument logique giveNames qui est utilisé pour les entrées de liste. Voir ?setDT exemples pour en savoir plus.

Ceci est conforme à data.table convention d'appellation - tous set* modifie par référence. := est le seul autre qui modifie également par référence.


Suivant votre montage :

Oui, vous pouvez convertir un data.frame en data.table par référence comme suit :

setattr(data, "class", c("data.table", "data.frame"))
data.table:::settruelength(data, 0L)
invisible(alloc.col(data))

La ligne,

data <- rep(data.frame(rnorm(N)), K)

crée une liste de "numériques" et n'est pas vraiment un data.frame. Ainsi, votre question est de savoir si vous pouvez convertir une liste de vecteurs en un tableau de données sans copie. Vous devriez probablement modifier votre question pour refléter cela (pour que d'autres puissent en profiter plus tard).

Oui, vous pouvez le faire en regardant data.table:::as.data.table.list . Bien sûr, ici, une copie est faite pour que la liste d'entrée ne soit pas modifiée par référence. Mais dans votre cas, cela ne vous dérange pas de la modifier par référence. Vous pouvez simplement le faire :

setattr(data, "names", paste("V", seq_len(K), sep = ""))
setattr(data, "row.names", .set_row_names(N))
setattr(data, "class", c("data.table", "data.frame"))
data.table:::settruelength(data, 0L)
invisible(alloc.col(data))

Voici un test pour montrer si une copie est faite :

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

gc(reset=TRUE)
#             used  (Mb) gc trigger   (Mb)  max used  (Mb)
# Ncells    360659  19.3     667722   35.7    360659  19.3
# Vcells 100537375 767.1  322372740 2459.6 100537375 767.1

tracemem(data)
# [1] "<0x7ff68a4d3df0>"

setattr(data, "names", paste("V", seq_len(K), sep = ""))
setattr(data, "row.names", .set_row_names(N))
setattr(data, "class", c("data.table", "data.frame"))
data.table:::settruelength(data, 0L)
# NULL

invisible(alloc.col(data))

class(data)
# [1] "data.table" "data.frame"

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X