6

只是为了自己清理一些东西,我想更好地了解何时制作副本以及何时不在data.table. 正如这个问题所指出的,确切地了解何时 data.table 是对另一个 data.table 的引用(相对于副本),如果只是运行以下命令,那么您最终会修改原始数据:

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=1:10)
DT
     a
 1:  1
 2:  2
 3:  3
 4:  4
 5:  5
 6:  6
 7:  7
 8:  8
 9:  9
10: 10

newDT = DT[a<11]
newDT
     a
 1:  1
 2:  2
 3:  3
 4:  4
 5:  5
 6:  6
 7:  7
 8:  8
 9:  9
10: 10

newDT[1:5,a:=0L]

newDT
     a
 1:  0
 2:  0
 3:  0
 4:  0
 5:  0
 6:  6
 7:  7
 8:  8
 9:  9
10: 10

DT
     a
 1:  1
 2:  2
 3:  3
 4:  4
 5:  5
 6:  6
 7:  7
 8:  8
 9:  9
10: 10

据我了解,发生这种情况的原因是,当您执行i语句时,会data.table返回一个全新的表,而不是对旧的 select 元素占用的内存的引用data.table。这是正确和真实的吗?

编辑:对不起,我的意思i不是j(在上面改变了这个)

4

1 回答 1

8

newDT在第二个示例中创建时,您正在评估i(不是j)。:=j参数中通过引用分配。语句中没有等价物i,因为自引用过度分配列,但不分配行。

Adata.table是一个列表。它的长度 == 列数,但已过度分配,因此您可以添加更多列而无需复制整个表(例如使用:=in j

如果我们检查 data.table,那么我们可以看到truelength( tl = 100)——这是列指针槽的数量

 .Internal(inspect(DT))
@1427d6c8 19 VECSXP g0c7 [OBJ,NAM(2),ATT] (len=1, tl=100)
  @b249a30 13 INTSXP g0c4 [NAM(2)] (len=10, tl=0) 1,2,3,4,5,...

在 data.table 每个元素都有长度10,和tl=0。目前没有方法可以增加truelength列的数量以允许通过引用附加额外的行。

?truelength

目前,只是列指针的列表向量被过度分配(即 truelength(DT)),而不是列向量本身,这将在未来允许快速行 insert()

当您评估i时,data.table不会检查您是否以与原始相同的顺序返回所有行(然后仅在这种情况下不复制),它只是返回副本。

于 2013-04-08T22:56:13.093 回答