Mam mały problem ze zrozumieniem właściwości przejścia przez odniesienie data.table
. Niektóre operacje wydają się „łamać” odniesienie i chciałbym dokładnie zrozumieć, co się dzieje.
Po utworzeniu data.table
z innego data.table
(poprzez <-
, a następnie aktualizację nowej tabeli o :=
, oryginalna tabela również ulega zmianie. Jest to oczekiwane, zgodnie z:
?data.table::copy
i stackoverflow: pass-by-reference-the-operator-in-the-data-table-package
Oto przykład:
library(data.table)
DT <- data.table(a=c(1,2), b=c(11,12))
print(DT)
# a b
# [1,] 1 11
# [2,] 2 12
newDT <- DT # reference, not copy
newDT[1, a := 100] # modify new DT
print(DT) # DT is modified too.
# a b
# [1,] 100 11
# [2,] 2 12
Jeśli jednak wstawię nieopartą :=
na modyfikacji modyfikację między <-
przypisaniem a :=
powyższymi liniami, DT
nie będzie ona już modyfikowana:
DT = data.table(a=c(1,2), b=c(11,12))
newDT <- DT
newDT$b[2] <- 200 # new operation
newDT[1, a := 100]
print(DT)
# a b
# [1,] 1 11
# [2,] 2 12
Wygląda więc na to, że newDT$b[2] <- 200
linia w jakiś sposób „łamie” odniesienie. Domyślam się, że to w jakiś sposób wywołuje kopię, ale chciałbym w pełni zrozumieć, jak R traktuje te operacje, aby upewnić się, że nie wprowadzam potencjalnych błędów w moim kodzie.
Byłbym bardzo wdzięczny, gdyby ktoś mi to wyjaśnił.
źródło
<-
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.Odpowiedzi:
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. Tedata.table
cechy:=
iset()
przypisanie przez referencję do obiektu bez względu są one przekazywane. Więc jeśli ten obiekt został wcześniej skopiowany (przez podzadanie<-
lub jawniecopy(DT)
), to kopia jest modyfikowana przez odwołanie.Zauważ, że nawet
a
wektor został skopiowany (inna wartość szesnastkowa oznacza nową kopię wektora), nawet jeślia
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:=
iset()
zostały wprowadzonedata.table
.Teraz za pomocą naszych skopiowanych
newDT
możemy zmodyfikować go przez odniesienie: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:Te wartości szesnastkowe są takie same, jak wartości pierwotne, które widzieliśmy
DT
powyżej. Wpiszexample(copy)
więcej przykładów, używająctracemem
i porównując zdata.frame
.Btw, jeśli
tracemem(DT)
toDT[2,b:=600]
zobaczysz jeden raport zgłoszony. To jest kopia pierwszych 10 wierszy, któreprint
robi metoda. Kiedy owinięteinvisible()
lub po nazwie wewnątrz funkcji lub skrypcieprint
metoda nie jest tzw.Wszystko to dotyczy również funkcji wewnętrznych; tzn.
:=
iset()
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 dotyczydata.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).źródło
->
przypisanie, zmienia lokalizację pamięci. Niezmienione wektory utrzymują lokalizację pamięci wektorów pierwotnej ramki danych.data.table
Opisane tutaj zachowanie s jest bieżącym zachowaniem od 1.12.2.Krótkie podsumowanie.
<-
zdata.table
jest jak baza; tzn. nie jest pobierana żadna kopia, dopóki nie zostanie wykonana podpozycja<-
(np. zmiana nazw kolumn lub zmiana elementu, np.DT[i,j]<-v
). Następnie pobiera kopię całego obiektu, podobnie jak baza. To się nazywa kopiowanie przy zapisie. Myślę, że byłby lepiej znany jako kopiowanie na poddziały! NIE kopiuje, gdy używasz specjalnego:=
operatora lubset*
funkcji udostępnianych przezdata.table
. Jeśli masz duże dane, prawdopodobnie zechcesz ich użyć.:=
iset*
NIE KOPIUJEdata.table
, NAWET W RAMACH FUNKCJI.Biorąc pod uwagę przykładowe dane:
Poniższe po prostu „wiąże” inną nazwę
DT2
z tym samym obiektem danych powiązanym obecnie z tą nazwąDT
:To nigdy nie kopiuje i nigdy też nie jest kopiowane w bazie. Po prostu zaznacza obiekt danych, aby R wiedział, że dwie różne nazwy (
DT2
iDT
) wskazują na ten sam obiekt. I tak R będzie musiał skopiować obiekt, jeśli któryś z nich zostanie później przypisany .To też jest idealne dla
data.table
. To:=
nie do tego. Poniżej znajduje się celowy błąd, który:=
nie dotyczy tylko wiązania nazw obiektów::=
służy do przypisywania przez odniesienie. Ale nie używasz go tak, jak w bazie:używasz go w ten sposób:
To zmieniło się
DT
przez odniesienie. Załóżmy, że dodajesz nową kolumnęnew
przez odniesienie do obiektu danych, nie musisz tego robić:ponieważ RHS już zmieniono
DT
przez odniesienie. Dodatkową korzyściąDT <-
jest niezrozumienie, co się:=
dzieje. Możesz to tam napisać, ale jest to zbyteczne.DT
zmienia się przez odniesienie:=
, NAWET W RAMACH FUNKCJI:data.table
jest dla dużych zestawów danych, pamiętaj. Jeśli masz 20 GBdata.table
pamięci, musisz to zrobić. To bardzo przemyślana decyzja projektowadata.table
.Oczywiście można wykonać kopie. Musisz tylko powiedzieć data.table, że na pewno chcesz skopiować zestaw danych 20 GB, korzystając z
copy()
funkcji:Aby uniknąć kopiowania, nie używaj przypisania typu podstawowego ani aktualizacji:
Jeśli chcesz mieć pewność, że aktualizujesz przez referencję, skorzystaj
.Internal(inspect(x))
z wartości adresowych pamięci składników (patrz odpowiedź Matthew Dowle'a).Pisząc
:=
wj
ten sposób, możesz dokonać podpozycji przez odniesienie według grupy . Możesz dodać nową kolumnę przez odniesienie według grupy. Właśnie dlatego:=
odbywa się to w ten sposób[...]
:źródło