为了清除自己的一些内容,我想更好地了解复制何时以及何时不在data.table
。正如这个问题指出Understanding exactly when a data.table is a reference to (vs a copy of) another 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
(已在上面进行了更改)
答案 0 :(得分:8)
在第二个示例中创建newDT
时,您正在评估i
(而不是j
)。 :=
在j
参数中通过引用进行分配。 i
语句中没有等价物,因为自引用会分配列,但不会分配行。
data.table
是一个列表。它的长度==列数,但是已经过度分配,因此您可以添加更多列而不复制整个表格(例如在:=
中使用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
目前,它只是列指针的列表向量 过度分配(即真实长度(DT)),而不是列向量 本身,将来允许快速插入行()
当您评估i
时,data.table
不会检查您是否只是按原始顺序返回所有行(然后仅在此情况下不复制),它只返回副本。