【问题标题】:data.table merge on partial match of different columns in Rdata.table 合并 R 中不同列的部分匹配
【发布时间】:2018-08-21 06:20:21
【问题描述】:

这个问题之前可能已经被问过,但如果可能的话,我正在寻找一个 data.table 解决方案,而不使用其他包。我有一个 data.table DT1 作为参考:

> require(data.table)
> DT1 <- data.table(col1 = c("AA", "BA", "ABC", "ABC BC", "AB")
                  , col2 = c(1,4,5,3,2))
> DT1
     col1 col2
1:     AA    1
2:     BA    4
3:    ABC    5
4: ABC BC    3
5:     AB    2

我想根据 DT1 中的 col1 和 DT2 中的 col2 的部分匹配,将第二个 data.table DT2 与 DT1 合并,在 DT2 中创建一个 col3。

> DT2 <- data.table(col1 = c(0,5,2,7,1,0)
                  , col2 = c("BA", "ABC", "DC", "AA", "AB", "R AB"))
> DT2
   col1 col2
1:    0   BA
2:    5  ABC
3:    2   DC
4:    7   AA
5:    1   AB
6:    0  R AB

想要的输出

 > desired_output <- data.table(col1 = c(0,5,5,2,7,1,1,1,0)
                                 , col2 = c("BA", "ABC", "ABC", "DC", "AA",  "AB", "AB", "AB", "R AB")
                                 , col3 = c(4,5,3,NA,1,5,3,2,2))
> desired_output
   col1 col2 col3
1:    0   BA    4
2:    5  ABC    5
3:    5  ABC    3
4:    2   DC   NA
5:    7   AA    1
6:    1   AB    5
7:    1   AB    3
8:    1   AB    2
9:    0  R AB   2

是否有任何优雅的方法可以使用 data.table 操作来做到这一点?如果不是那么乐意考虑其他解决方案。这将在一个非常大的数据集上运行。


编辑:指定部分匹配的条件,如果 DT1 中的 col1 字符串是 DT2 中 col2 字符串的子集,则匹配(DT2 中 col2 的字符串是字符串的子集) DT1 中的 col1)。两种方式的 grepl?

col1/DT1    col2/DT2
  "AB"       "There is ABhere"    # it's a match
  "ABC"      "someABC"            # it's a match
  "ABC BC"   "ABC"                # it's a reverse match
  "DR"       "ADD"                # no match
  "BA"       "HABAHA"             # two matches

【问题讨论】:

标签: r merge data.table matching partial


【解决方案1】:

考虑到问题的维度 (DT1 [(1:50,000), (1:25)] - DT2[(1:50,000,000), (1:55)]),做一个 CJ 可能是不可行的做双向grepl之前的ID。

分解不同类型的匹配/大约。匹配,我们可以 1)首先寻找完全匹配,2)然后大约。匹配 DT1 中的子字符串可以在 DT2 中找到,然后,3) 反之亦然。

最后,我们对所有结果进行行绑定,并在原始 DT2 和行绑定结果之间进行左连接以获得所需的输出。

exactMatches <- DT1[DT2, on=c("ID1"="ID2"), nomatch=0L][,
    ID2 := ID1]

substr1in2 <- DT2[, c(.SD, DT1[grepl(ID2, ID1) & ID1 != ID2]), 
    by=1:DT2[,.N]][!is.na(VAL1), -1L]

substr2in1 <- DT1[, c(.SD, DT2[grepl(ID1, ID2) & ID2 != ID1]), 
    by=1:DT1[,.N]][!is.na(VAL2), -1L]

binded <- rbindlist(list(exactMatches, substr1in2, substr2in1), 
    use.names=TRUE, fill=TRUE)

binded[DT2, on=.(ID2, VAL2)]

输出:

       ID1 VAL1 VAL2  ID2
 1:     BA    4    0   BA
 2:    ABC    5    5  ABC
 3: ABC BC    3    5  ABC
 4:     AB    2    5  ABC
 5:   <NA>   NA    2   DC
 6:     AA    1    7   AA
 7:     AB    2    1   AB
 8:    ABC    5    1   AB
 9: ABC BC    3    1   AB
10:     AB    2    0 R AB

我更改了一些列名以使代码更具可读性。数据:

DT1 <- data.table(ID1 = c("AA", "BA", "ABC", "ABC BC", "AB"), 
    VAL1 = c(1,4,5,3,2))

DT2 <- data.table(VAL2 = c(0,5,2,7,1,0),
    ID2 = c("BA", "ABC", "DC", "AA", "AB", "R AB"))

【讨论】:

  • 感谢@chinsoon12,这已经很好了。但是,当前解决方案的问题是,当 grepl(ID, PATTERN) 返回 VAL1 时,grepl 需要有两种方式,或者至少相反。不幸的是,我最初的示例没有显示这种情况,但我编辑了问题以进行澄清(可以在匹配案例中看到)
  • 我在 DT2 中增加了一行,用于反向部分匹配
  • 你的 DT1 和 DT2 的尺寸是多少?
  • DT1 [(1:50,000), (1:25)] - DT2[(1:50,000,000), (1:55) ] 如果需要,可以将 DT2 分成更小的集合
猜你喜欢
  • 1970-01-01
  • 2021-04-16
  • 2012-05-23
  • 1970-01-01
  • 2020-09-24
  • 2021-11-19
  • 2020-06-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多