2 回答
TA贡献1829条经验 获得超6个赞
是的,它是在R中使用的<-(或=或->)的副本。整体对象。您可以使用tracemem(DT)和.Internal(inspect(DT)),如下所示。这个data.table特征:=和set()通过引用将它们传递给任何对象。因此,如果该对象以前被复制(通过subas签名)<-或显式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/nol,而不是3)。
TA贡献2012条经验 获得超12个赞
简单总结一下。
<-
data.table
<-
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
DT2
DT
data.table
:=
:=
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
new
DT <- DT[,new:=1L]
DT
DT <-
:=
DT
:=
f <- function(X){ X[,new2:=2L] return("something else")}f(DT) # will change DTDT2 <- DT f(DT) # will change both DT and DT2 (they're the same data object)
data.table
data.table
data.table
.
copy()
DT3 <- copy(DT) # rather than DT3 <- DTDT3[,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]
- 2 回答
- 0 关注
- 788 浏览
添加回答
举报