如果您想将B
的b
值添加到A
中,最好是将A
与B
连接,并通过引用更新A
,操作如下:
A[B, on = 'a', bb := i.b]
which gives:
> A
a b bb
1: 1 12 NA
2: 2 13 13
3: 3 14 14
4: 4 15 NA
B[A, on='a']
只是将结果打印到控制台,使用
A <- B[A, on='a']
可以将结果返回到
A
中。但使用
A[B, on = 'a', bb := i.b]
比
A <- B[A, on = 'a']
更好,因为它具有更高的内存效率,能够使
A
在内存中位置不变。
> address(A)
[1] "0x102afa5d0"
> A[B, on = 'a', bb := i.b]
> address(A)
[1] "0x102afa5d0"
另一方面,使用
A <- B[A, on = 'a']
,将创建一个新对象并将其保存在内存中作为
A
,因此在内存中具有另一个位置:
> address(A)
[1] "0x102abae50"
> A <- B[A, on = 'a']
> address(A)
[1] "0x102aa7e30"
使用merge(merge.data.table)会导致内存位置类似地发生变化:
数据表的合并可以通过 merge
函数实现,合并后的结果会占用新的内存空间。
> address(A)
[1] "0x111897e00"
> A <- merge(A, B, by = 'a', all.x = TRUE)
> address(A)
[1] "0x1118ab000"
为了提高内存效率,因此最好使用“按引用连接更新”语法:
'update-by-reference-join'。
A[B, on = 'a', bb := i.b]
虽然像这样的小数据集不会有明显的差异,但它确实会对像 data.table
这样被设计用于处理大型数据集的工具产生影响。
值得一提的是,A
的顺序仍然保持不变。
为了查看速度和内存使用情况的影响,让我们使用一些更大的数据集进行基准测试(有关数据,请参见下面“使用数据”部分的第二部分):
library(bench)
bm <- mark(AA <- BB[AA, on = .(aa)],
AA[BB, on = .(aa), cc := cc],
iterations = 1)
提供以下相关测量数据:
> bm[,c(1,3,5)]
# A tibble: 2 x 3
expression median mem_alloc
<bch:expr> <bch:tm> <bch:byt>
1 AA <- BB[AA, on = .(aa)] 4.98s 4.1GB
2 AA[BB, on = .(aa), `:=`(cc, cc)] 560.88ms 384.6MB
因此,在这个设置中,'update-by-reference-join' 大约快了9倍,并且消耗的内存少了11倍。
注:速度和内存使用方面的收益可能因不同设置而异。
---
使用的数据:
A <- data.table(a = 1:4, b = 12:15)
B <- data.table(a = 2:3, b = 13:14)
set.seed(2019)
AA <- data.table(aa = 1:1e8, bb = sample(12:19, 1e7, TRUE))
BB <- data.table(aa = sample(AA$a, 2e5), cc = sample(2:8, 2e5, TRUE))
all.x = TRUE
。如果你想要进行全外连接,可以使用all = TRUE
。 - ytk