Konwertuj ramkę danych na plik data.table bez kopiowania

81

Mam dużą ramkę danych (rzędu kilku GB), którą chciałbym przekonwertować na plik data.table. Użycie as.data.tabletworzy kopię ramki danych, co oznacza, że ​​potrzebuję dostępnej pamięci co najmniej dwukrotnie większej niż dane. Czy istnieje sposób na wykonanie konwersji bez kopii?

Oto prosty przykład do zademonstrowania:

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

Z wyjściem:

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
ytsaig
źródło

Odpowiedzi:

93

Jest to dostępne od wersji 1.9.0 + . Z WIADOMOŚCI :

o Po tym wpisie SOsetDT zaimplementowano funkcję, która przyjmuje list(nazwane i / lub nienazwane), data.frame(lub data.table) jako dane wejściowe i zwraca ten sam obiekt jako data.table odwołanie (bez żadnej kopii). Zobacz ?setDTprzykłady po więcej.

Jest to zgodne z data.tablekonwencją nazewnictwa - wszystkie set*funkcje są modyfikowane przez odniesienie. :=jest jedynym innym, który również modyfikuje przez odniesienie.

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

Zobacz historię starszych (teraz nieaktualnych) odpowiedzi.

Bieg
źródło
@Arun: Dzięki za szczegółową odpowiedź. Właściwie pytałem, jak przekonwertować ramkę danych na tabelę danych, ale byłem niechlujny w tworzeniu przykładu zabawki, zaktualizuję moje pytanie, aby uczynić z niego ramkę danych. Czy ten sam pomysł zadziała wtedy w przypadku ramki danych, np. Pozbycie się pierwszych dwóch setattr, ponieważ ramka danych już je zawiera i zachowa resztę?
ytsaig
@YT, jeśli masz na myśli przeniesienie „data.frame” do „data.table”, to oczywiście to, co mówisz, jest słuszne. Jeśli masz na myśli listę data.frames, musisz je powiązać (kolumnami lub wierszami) przed ustawieniem klasy i alokacją.
Arun
@Arun, miałem na myśli to pierwsze, pojedynczą ramkę danych do tabeli danych, zredagowałem pytanie, aby, mam nadzieję, lepiej je odzwierciedlić. Jeszcze raz dziękuję za sprytne rozwiązanie. Mogę przyjąć odpowiedź bez zmian lub poczekać, czy chcesz ją edytować, aby pasowała do poprawionego pytania.
ytsaig
2
Może ten post od Matthew pomoże rzucić więcej światła truelength.
Arun
3
@eddi Przed R2.14.0, truelengthelement nagłówka wektora R nie został zainicjowany przez R. W C, jeśli nie zainicjujesz zmiennej, ma ona niezdefiniowaną zawartość (cokolwiek znajdowało się w tym fragmencie pamięci RAM wcześniej). data.table()i podobni twórcy inicjują wartość truelength0 przed wywołaniem alloc.colzgodności z wersją wcześniejszą niż R 2.14.0. alloc.colwygląda truelengthjak dane wejściowe (0 oznacza prawdziwą długość == długość). W pewnym momencie pomyślałem, że data.table będzie musiała z tego powodu zależeć od R> = 2.14.0, ale udało mi się zachować R> = 2.12.0. Testuję z R2.12.0 przed każdą wersją do CRAN.
Matt Dowle,