Так, саме підрозділ R використовує <-
(або =
або ->
), що робить копію всього об'єкта. Ви можете простежити це за допомогою tracemem(DT)
та .Internal(inspect(DT))
, як показано нижче. В data.table
особливості :=
і set()
правонаступник по відношенню до будь-якого об'єкту , вони передаються. Отже, якщо цей об'єкт був скопійований раніше (шляхом переназначення <-
або явного copy(DT)
), то це копія, що змінюється за допомогою посилання.
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..
Зверніть увагу, як навіть a
вектор було скопійовано (різне шістнадцяткове значення вказує на нову копію вектора), навіть якщо a
це не було змінено. Навіть ціле b
копіювання було скопійовано, а не просто змінило елементи, які потрібно змінити. Цього важливо уникати для великих даних, а чому :=
і до set()
яких ознайомилися data.table
.
Тепер, скопійовані newDT
ми можемо змінити його за посиланням:
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 ..
Зауважте, що всі 3 шістнадцяткові значення (вектор точок стовпця та кожен із 2 стовпців) залишаються незмінними. Таким чином, він був по-справжньому модифікований шляхом посилання без копій взагалі.
Або ми можемо змінити оригінал DT
за посиланням:
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..
Ці шістнадцяткові значення збігаються з початковими значеннями, які ми бачили DT
вище. Введіть example(copy)
для отримання більше прикладів використання tracemem
та порівняння data.frame
.
До речі, якщо ви tracemem(DT)
потім DT[2,b:=600]
повідомив , ви побачите один екземпляр. Це копія перших 10 рядків, яку print
робить метод. Якщо обгортати invisible()
функцію або сценарій або коли його викликати, print
метод не викликається.
Все це стосується і внутрішніх функцій; тобто, :=
і set()
не копіювати на записи, навіть в межах функцій. Якщо вам потрібно змінити локальну копію, то зателефонуйте x=copy(x)
на початку функції. Але пам’ятайте data.table
, що для великих даних (а також більш швидкі переваги програмування для малих даних). Ми свідомо не хочемо копіювати великі об'єкти (ніколи). Як наслідок, нам не потрібно враховувати звичайне правило 3 * робочого фактора пам'яті. Ми намагаємось лише потрібну робочу пам'ять розміром, як один стовпчик (тобто коефіцієнт робочої пам'яті 1 / нкол, а не 3).
<-
замість=
основного завдання в R (наприклад, Google: google.github.io/styleguide/Rguide.xml#assignment ). Але це означає, що маніпуляція з data.table не буде функціонувати так само, як маніпулювання кадрами даних, і тому далеко не заміна заміни для кадру даних.