R 准确理解data.table何时是另一个data.table的引用(相对于副本)

R 准确理解data.table何时是另一个data.table的引用(相对于副本),r,reference,copy,data.table,assignment-operator,R,Reference,Copy,Data.table,Assignment Operator,我在理解data.table的pass-by-reference属性时有点困难。有些操作似乎“破坏”了引用,我想确切地了解发生了什么 从另一个data.table创建data.table(通过是的,它是使用在R中的子分配)时,生成整个对象的副本。您可以使用tracemem(DT)和.Internal(inspect(DT))来跟踪它,如下所示。data.table的功能是:=和set()通过引用将其分配给所传递的任何对象。因此,如果该对象以前被复制(由子授权复制),则只需快速汇总即可。 我刚刚发

我在理解
data.table
的pass-by-reference属性时有点困难。有些操作似乎“破坏”了引用,我想确切地了解发生了什么


从另一个
data.table
创建
data.table
(通过
是的,它是使用
在R中的子分配)时,生成整个对象的副本。您可以使用
tracemem(DT)
.Internal(inspect(DT))
来跟踪它,如下所示。
data.table
的功能是
:=
set()
通过引用将其分配给所传递的任何对象。因此,如果该对象以前被复制(由子授权
复制),则只需快速汇总即可。

我刚刚发现了这个“功能”互联网上广泛提倡何时使用
这种行为是可取的?有趣的是,data.frame对象不会出现复制整个对象的行为。在复制的data.frame中,只有通过
->
赋值直接更改的向量会更改内存位置。未更改的向量维护原始data.frame的向量的内存位置。此处描述的
data.table
s的行为是1.12.2中的当前行为。
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 = 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
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..
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 ..
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 <- data.table(a=c(1,2), b=c(11,12))
DT2 <- DT
DT2 := DT    # not what := is for, not defined, gives a nice error
DT[3,"foo"] := newvalue    # not like this
DT[3,foo:=newvalue]    # like this
DT <- DT[,new:=1L]
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)
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() 
DT[, newcol:=mean(x), by=group]