Tak, to poddział w R za pomocą <-
(lub =
lub ->
), który tworzy kopię całego obiektu. Możesz to prześledzić za pomocą tracemem(DT)
i .Internal(inspect(DT))
, jak poniżej. Te data.table
cechy :=
i set()
przypisanie przez referencję do obiektu bez względu są one przekazywane. Więc jeśli ten obiekt został wcześniej skopiowany (przez podzadanie <-
lub jawnie copy(DT)
), to kopia jest modyfikowana przez odwołanie.
DT <- data.table(a = c(1, 2), b = c(11, 12))
newDT <- DT
.Internal(inspect(DT))
# @0000000003B7E2A0 19 VECSXP g0c7 [OBJ,NAM(2),ATT] (len=2, tl=100)
# @00000000040C2288 14 REALSXP g0c2 [NAM(2)] (len=2, tl=0) 1,2
# @00000000040C2250 14 REALSXP g0c2 [NAM(2)] (len=2, tl=0) 11,12
# ATTRIB: # ..snip..
.Internal(inspect(newDT)) # precisely the same object at this point
# @0000000003B7E2A0 19 VECSXP g0c7 [OBJ,NAM(2),ATT] (len=2, tl=100)
# @00000000040C2288 14 REALSXP g0c2 [NAM(2)] (len=2, tl=0) 1,2
# @00000000040C2250 14 REALSXP g0c2 [NAM(2)] (len=2, tl=0) 11,12
# ATTRIB: # ..snip..
tracemem(newDT)
# [1] "<0x0000000003b7e2a0"
newDT$b[2] <- 200
# tracemem[0000000003B7E2A0 -> 00000000040ED948]:
# tracemem[00000000040ED948 -> 00000000040ED830]: .Call copy $<-.data.table $<-
.Internal(inspect(DT))
# @0000000003B7E2A0 19 VECSXP g0c7 [OBJ,NAM(2),TR,ATT] (len=2, tl=100)
# @00000000040C2288 14 REALSXP g0c2 [NAM(2)] (len=2, tl=0) 1,2
# @00000000040C2250 14 REALSXP g0c2 [NAM(2)] (len=2, tl=0) 11,12
# ATTRIB: # ..snip..
.Internal(inspect(newDT))
# @0000000003D97A58 19 VECSXP g0c7 [OBJ,NAM(2),ATT] (len=2, tl=100)
# @00000000040ED7F8 14 REALSXP g0c2 [NAM(2)] (len=2, tl=0) 1,2
# @00000000040ED8D8 14 REALSXP g0c2 [NAM(2)] (len=2, tl=0) 11,200
# ATTRIB: # ..snip..
Zauważ, że nawet a
wektor został skopiowany (inna wartość szesnastkowa oznacza nową kopię wektora), nawet jeśli a
nie został zmieniony. Nawet całość b
została skopiowana, a nie tylko zmiana elementów, które należy zmienić. Jest to ważne, aby unikać dużych danych oraz dlaczego :=
i set()
zostały wprowadzone data.table
.
Teraz za pomocą naszych skopiowanych newDT
możemy zmodyfikować go przez odniesienie:
newDT
# a b
# [1,] 1 11
# [2,] 2 200
newDT[2, b := 400]
# a b # See FAQ 2.21 for why this prints newDT
# [1,] 1 11
# [2,] 2 400
.Internal(inspect(newDT))
# @0000000003D97A58 19 VECSXP g0c7 [OBJ,NAM(2),ATT] (len=2, tl=100)
# @00000000040ED7F8 14 REALSXP g0c2 [NAM(2)] (len=2, tl=0) 1,2
# @00000000040ED8D8 14 REALSXP g0c2 [NAM(2)] (len=2, tl=0) 11,400
# ATTRIB: # ..snip ..
Zauważ, że wszystkie 3 wartości szesnastkowe (wektor punktów kolumny i każda z 2 kolumn) pozostają niezmienione. Więc został naprawdę zmodyfikowany przez odniesienie bez żadnych kopii.
Lub możemy zmodyfikować oryginał DT
przez odniesienie:
DT[2, b := 600]
# a b
# [1,] 1 11
# [2,] 2 600
.Internal(inspect(DT))
# @0000000003B7E2A0 19 VECSXP g0c7 [OBJ,NAM(2),ATT] (len=2, tl=100)
# @00000000040C2288 14 REALSXP g0c2 [NAM(2)] (len=2, tl=0) 1,2
# @00000000040C2250 14 REALSXP g0c2 [NAM(2)] (len=2, tl=0) 11,600
# ATTRIB: # ..snip..
Te wartości szesnastkowe są takie same, jak wartości pierwotne, które widzieliśmy DT
powyżej. Wpisz example(copy)
więcej przykładów, używając tracemem
i porównując z data.frame
.
Btw, jeśli tracemem(DT)
to DT[2,b:=600]
zobaczysz jeden raport zgłoszony. To jest kopia pierwszych 10 wierszy, które print
robi metoda. Kiedy owinięte invisible()
lub po nazwie wewnątrz funkcji lub skrypcie print
metoda nie jest tzw.
Wszystko to dotyczy również funkcji wewnętrznych; tzn. :=
i set()
nie kopiuj podczas zapisu, nawet w obrębie funkcji. Jeśli musisz zmodyfikować kopię lokalną, zadzwoń x=copy(x)
na początku funkcji. Pamiętaj jednak, że dotyczy data.table
to dużych danych (a także szybszych korzyści programowania dla małych danych). Celowo nie chcemy kopiować dużych obiektów (nigdy). W rezultacie nie musimy dopuszczać zwykłej reguły 3 * współczynnika pamięci operacyjnej. Staramy się potrzebować pamięci roboczej tak dużej jak jedna kolumna (tj. Współczynnik pamięci roboczej 1 / ncol zamiast 3).
<-
zamiast=
podstawowego zadania w R (np. Przez Google: google.github.io/styleguide/Rguide.xml#assignment ). Oznacza to jednak, że manipulowanie tabelą danych nie będzie działało w taki sam sposób, jak manipulowanie ramką danych, a zatem dalekie jest od zastąpienia ramki danymi.