Понимание того, когда именно данные.таблица-это ссылка на (против копии) другие данные.стол


у меня возникли небольшие проблемы с пониманием свойств pass-by-reference 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 обрабатывает эти операции, чтобы убедитесь, что я не ввожу потенциальные ошибки в моем коде.

Я был бы очень признателен, если бы кто-нибудь объяснил мне это.

2 156

2 ответа:

Да, это подзадача в R с помощью <- (или = или ->), что делает копию весь

просто краткое резюме.

<- С data.table точно так же, как base; т. е. никакая копия не берется до тех пор, пока подзадача не будет выполнена впоследствии с <- (например, изменение имен столбцов или изменение элемента, например DT[i,j]<-v). Затем он берет копию всего объекта так же, как база. Это известно как копирование на запись. Было бы лучше известно как копия-на-субассин, я думаю! Он не копируется при использовании специального := оператора, или set* функции, предусмотренные data.table. Если у вас есть большие данные, которые вы, вероятно, хотите использовать их. := и set* не будет копировать data.table, ДАЖЕ В ПРЕДЕЛАХ ФУНКЦИЙ.

учитывая этот пример данных:

DT <- data.table(a=c(1,2), b=c(11,12))

следующее просто "связывает" другое имя DT2 к тому же объекту данных привязан в настоящее время привязан к имени DT:

DT2 <- DT

это никогда не копирует, и никогда не копирует в базу либо. Он просто помечает объект данных, чтобы R знал, что два разных имени (DT2 и DT) указывают на тот же объект. И поэтому R нужно будет скопировать объект, Если либо subassigned потом.

это идеально подходит для data.table тоже. Элемент := не для этого. Таким образом, следующее является преднамеренной ошибкой как := не только для привязки имен объекта :

DT2 := DT    # not what := is for, not defined, gives a nice error

:= на subassigning по ссылке. Но вы не используете его, как вы бы в базе :

DT[3,"foo"] := newvalue    # not like this

вы используйте его так:

DT[3,foo:=newvalue]    # like this

что изменилось DT по ссылке. Скажем, вы добавляете новый столбец new со ссылкой на объект данных, нет необходимости делать это :

DT <- DT[,new:=1L]

потому что RHS уже изменился DT по ссылке. Дополнительные DT <- - это значит не понимать, что := делает. Вы можете написать его там, но это лишнее.

DT изменяется по ссылке, по :=, ДАЖЕ В ПРЕДЕЛАХ ФУНКЦИЙ :

f <- function(X){
    X[,new2:=2L]
    return("something else")
}
f(DT)   # will change DT

DT2 <- DT
f(DT)   # will change both DT and DT2 (they're the same data object)

data.table для больших наборов данных, помните. Если у вас есть 20GB data.table в памяти, то вам нужен способ, чтобы сделать это. Это очень продуманное дизайнерское решение data.table.

копии могут быть сделаны, конечно. Вам просто нужно рассказать данные.таблица, в которой вы уверены, что хотите скопировать свой набор данных 20GB, используя copy() функция :

DT3 <- copy(DT)   # rather than DT3 <- DT
DT3[,new3:=3L]     # now, this just changes DT3 because it's a copy, not DT too.

чтобы избежать копирования, не используйте назначение базового типа или обновление:

DT$new4 <- 1L                 # will make a copy so use :=
attr(DT,"sorted") <- "a"      # will make a copy use setattr() 

если вы хотите быть уверены, что вы обновляете по ссылке использовать .Internal(inspect(x)) и посмотрите на значения адресов памяти составляющих (см. ответ Мэтью Доула).

писать := на j как это позволяет вам назначить по ссылке группы. Вы можете добавить новый столбец по ссылке по группам. Так вот почему := делается таким образом внутри [...]:

DT[, newcol:=mean(x), by=group]