首页 > 解决方案 > 匹配一个变量后,仅将一个变量从一个 R data.table 复制到另一个

问题描述

我可以通过类似的方式将数据框中的列的匹配副本复制到另一个中

DF2$y <- DF1[match(DF2$id2, DF1$id1), "z"]  # DF1 and DF2 are data frames

哪里DF2$id2匹配DF1$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?

标签: rdata.table

解决方案


如果我理解正确,OP 想要将列zfrom附加DT1到id 列匹配的列DT2y

使用,这可以使用更新连接来解决:

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 数百万行的大型生产数据集可能很方便。

警告

这是有效的,因为id1并且id2唯一的,示例用例就是这种情况。因此,请确保在更新重复值的连接时获得所需的内容。

让我们看看如果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][]

返回

   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

推荐阅读