У меня небольшие проблемы с пониманием свойств передачи по ссылке data.table
. Некоторые операции, кажется, «ломают» ссылку, и я хотел бы точно понять, что происходит.
При создании data.table
из другого data.table
(через <-
, затем обновляя новую таблицу :=
, исходная таблица также изменяется. Это ожидается согласно:
?data.table::copy
и stackoverflow: передача по ссылке-оператору-в-таблице-данных-пакета
Вот пример:
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
Однако, если я вставлю неосновную :=
модификацию между <-
назначением и :=
строками выше, DT
теперь больше не будет изменено:
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
Так что кажется, что newDT$b[2] <- 200
строка как-то «ломает» ссылку. Я предполагаю, что это как-то вызывает копию, но я хотел бы полностью понять, как R обрабатывает эти операции, чтобы не допустить потенциальных ошибок в моем коде.
Я был бы очень признателен, если бы кто-то мог мне это объяснить.
источник
<-
вместо=
базового назначения в R (например, Google: google.github.io/styleguide/Rguide.xml#assignment ). Но это означает, что манипулирование данными.таблицы не будет функционировать так же, как манипулирование фреймами данных, и, следовательно, это далеко не полная замена фрейма данных.Ответы:
Да, это суб-назначение в R с использованием
<-
(или=
или->
), которое делает копию всего объекта. Вы можете отследить это, используяtracemem(DT)
и.Internal(inspect(DT))
, как показано ниже. Вdata.table
особенности:=
иset()
правопреемник по отношению к любому объекту , они передаются. Таким образом, если этот объект был ранее скопирован (с помощью суб-<-
присвоения или явногоcopy(DT)
), то это копия, которая модифицируется по ссылке.Обратите внимание, что даже
a
вектор был скопирован (другое шестнадцатеричное значение указывает на новую копию вектора), даже еслиa
он не был изменен. Даже всеb
копирование было скопировано, а не просто изменены элементы, которые необходимо изменить. Это важно, чтобы избежать для больших данных, и почему:=
иset()
были представленыdata.table
.Теперь, с нашим скопированным,
newDT
мы можем изменить его по ссылке:Обратите внимание, что все 3 шестнадцатеричных значения (вектор точек столбцов и каждый из 2 столбцов) остаются неизменными. Так что он был действительно изменен по ссылке без копий вообще.
Или мы можем изменить оригинал
DT
по ссылке:Эти шестнадцатеричные значения совпадают с исходными значениями, которые мы видели
DT
выше. Введитеexample(copy)
дополнительные примеры с использованиемtracemem
и сравнение сdata.frame
.Кстати, если вы,
tracemem(DT)
тоDT[2,b:=600]
вы увидите одну копию сообщили. Это копия первых 10 строк, которыеprint
делает метод. При переносеinvisible()
или при вызове внутри функции или скриптаprint
метод не вызывается.Все это относится и к внутренним функциям; т.е.
:=
иset()
не копировать при записи даже внутри функций. Если вам нужно изменить локальную копию, вызовите ееx=copy(x)
в начале функции. Но помните,data.table
что для больших данных (а также преимущества быстрого программирования для небольших данных). Мы сознательно не хотим копировать большие объекты (никогда). В результате нам не нужно учитывать обычное эмпирическое правило с 3 * рабочим коэффициентом памяти. Мы стараемся использовать рабочую память размером не более одного столбца (т.е. коэффициент рабочей памяти равен 1 / ncol, а не 3).источник
->
назначения. Неизмененные векторы сохраняют в памяти местоположение векторов исходного data.frame. Поведениеdata.table
s, описанное здесь, является текущим поведением на 1.12.2.Просто быстрое подведение итогов.
<-
сdata.table
просто как база; т. е. копия не берется до тех пор, пока не будет выполнен поднабор с помощью<-
(например, изменение имен столбцов или изменение элемента, такого какDT[i,j]<-v
). Затем он берет копию всего объекта, как база. Это известно как копирование при записи. Думаю, будет более известным как copy-on-subassign! Он НЕ копирует, когда вы используете специальный:=
оператор илиset*
функции, предоставляемыеdata.table
. Если у вас есть большие данные, вы, вероятно, хотите использовать их вместо.:=
и неset*
будет копироватьdata.table
, даже в рамках функций.Учитывая данные этого примера:
Следующее просто «привязывает» другое имя
DT2
к тому же объекту данных, привязанному в данный момент к имениDT
:Это никогда не копирует и никогда не копирует в базу. Он просто помечает объект данных, чтобы R знал, что два разных имени (
DT2
иDT
) указывают на один и тот же объект. И поэтому R нужно будет скопировать объект , если либо являются subassigned на потом.Это также идеально подходит для
data.table
.:=
Не за это. Таким образом, следующее является преднамеренной ошибкой, поскольку:=
не только для привязки имен объектов::=
предназначен для поднабора по ссылке. Но вы не используете его как в базе:вы используете это так:
Это изменилось
DT
по ссылке. Скажем, вы добавляете новый столбецnew
по ссылке на объект данных, нет необходимости делать это:потому что RHS уже изменился
DT
по ссылке. ДополнительнымDT <-
является неправильное понимание того, что:=
делает. Вы можете написать это там, но это лишнее.DT
изменяется по ссылке:=
, ДАЖЕ В ФУНКЦИЯХ:data.table
для больших наборов данных, помните. Если у вас есть 20 ГБdata.table
памяти, вам нужен способ сделать это. Это очень обдуманное дизайнерское решениеdata.table
.Копии могут быть сделаны, конечно. Вам просто нужно сообщить data.table, что вы уверены, что хотите скопировать набор данных объемом 20 ГБ, используя
copy()
функцию:Чтобы избежать копирования, не используйте базовое назначение типа или обновление:
Если вы хотите быть уверены, что вы обновляете по ссылке, используйте
.Internal(inspect(x))
и посмотрите значения адресов памяти компонентов (см. Ответ Мэтью Доула).Запись
:=
вj
таком виде позволяет вам назначать ссылки по группам . Вы можете добавить новый столбец по ссылке по группе. Вот почему так:=
делается внутри[...]
:источник