在匹配一个变量后,只将一个变量从一个 R data.table 复制到另一个

Copy only one variable from one R data.table to another after matching on a variable

我可以通过类似

的方式将数据框中一列的匹配副本复制到另一列
DF2$y <- DF1[match(DF2$id2, DF1$id1), "z"]  # DF1 and DF2 are data frames

其中 DF2$id2DF1$id1 匹配。我想知道我可以用 数据表 为这种操作做些什么。我的数据表有数百万行和数百列。我完成了 setkey(DT1, id1)setkey(DT2, id2)

这个有效:

DT2[, y := DT1[match(DT2$id2, DT1$id1), "z"]]  # DT1 and DT2 are data tables

但我担心 match 部分可能需要很长时间。 (或者这是不可避免的?)

我知道我还可以使用列选择、merge 和重命名:

tmp <- DT1[, c("id1", "z")]  # column selection
DT3 <- merge(DT2, tmp, by.x = "id2", by.y = "id1", all.x = TRUE, suffixes = c("", ".y")) # merge
setnames(DT3, "z.y", "y")  # rename

(其中前两行可以写在一行上)但这似乎有点太复杂了。会有更简单快速的解决方案吗?

谢谢。

示例:

library(data.table)
DF1 <- data.frame(id1=2:4, x=LETTERS[1:3], z=11:13)
DF2 <- data.frame(id2=1:4, x=LETTERS[5:8], z=21:24)
DF1
#   id1 x  z
# 1   2 A 11
# 2   3 B 12
# 3   4 C 13
DF2
#   id2 x  z
# 1   1 E 21
# 2   2 F 22
# 3   3 G 23
# 4   4 H 24

DT1 <- data.table(DF1)
DT2 <- data.table(DF2)
setkey(DT1, id1)
setkey(DT2, id2)

DF2$y <- DF1[match(DF2$id2, DF1$id1), "z"]
DF2  # correct
#   id2 x  z  y
# 1   1 E 21 NA
# 2   2 F 22 11
# 3   3 G 23 12
# 4   4 H 24 13

DT2[, y := DT1[match(DT2$id2, DT1$id1), "z"]]
DT2
#    id2 x  z  y
# 1:   1 E 21 NA
# 2:   2 F 22 11
# 3:   3 G 23 12
# 4:   4 H 24 13
DT2[, y := NULL]

tmp <- DT1[, c("id1", "z")]
DT3 <- merge(DT2, tmp, by.x = "id2", by.y = "id1", all.x = TRUE, suffixes = c("", ".y"))
setnames(DT3, "z.y", "y")
DT3
#    id2 x  z  y
# 1:   1 E 21 NA
# 2:   2 F 22 11
# 3:   3 G 23 12
# 4:   4 H 24 13

## Simpler alternatives?

我有两个可能的想法:

  1. 使用 merge 和 select 列并在那里进行重命名
DT3 <- merge(DT2, DT1[, .(id1, y = z)], by.x = "id2", by.y = "id1", all.x = TRUE)
  1. 使用 data.tableon 语法。我直接根据这里的答案建立了这个解决方案,它展示了如何进行完整的外部连接:
unique_keys <- unique(c(DT1[, id1], DT2[, id2]))
DT3 <- DT2[DT1[.(unique_keys), .(id1, y = z)]]

如果我理解正确,OP 想要将列 zDT1 追加到 DT2 作为 ID 列匹配的列 y

使用 ,这可以使用 更新连接:

来解决
library(data.table)
DT2[DT1, on = .(id2 = id1), y := i.z]
DT2
   id2 x  z  y
1:   1 E 21 NA
2:   2 F 22 11
3:   3 G 23 12
4:   4 H 24 13

请注意 DT2 通过引用 更新 ,即没有复制整个数据对象。这对于 OP 的数百万行的大型生产数据集可能很方便。

警告

这是有效的,因为 id1id2 唯一的 ,示例用例就是这种情况。因此,请确保在对重复值执行 更新联接 时得到所需内容。

让我们看看如果 id1 列中有重复值会发生什么,例如

万一 DT1id1 == 4 重复

(DT1 <- data.table(id1 = c(2:4, 4), x = LETTERS[1:4], z = 11:14))
   id1 x  z
1:   2 A 11
2:   3 B 12
3:   4 C 13
4:   4 D 14

然后

DT2[DT1, on = .(id2 = id1), y := i.z][]

returns

   id2 x  z  y
1:   1 E 21 NA
2:   2 F 22 11
3:   3 G 23 12
4:   4 H 24 14

因此,更新加入

  • 尚未在 DT2 中创建额外的行(这可能是您可能希望避免复制大型数据集的原因),
  • 已选择最后出现的 z 以防出现多个匹配项。