通过引用两列

时间:2017-08-02 03:10:43

标签: r join merge data.table

我有两个数据表,我想根据两列中的值合并/连接,这两列可以在两个数据表中以相反的顺序出现。 以下是两个示例数据表:

library(data.table)
# df1
col1 <- c("aa", "bb", "cc", "dd") 
col2 <- c("bb", "zz", "dd", "ff") 
x <- c(130, 29, 122, 85)
dt1 <- data.table(col1, col2, x)

   col1  col2  x
1:   aa   bb 130
2:   bb   zz  29
3:   cc   dd 122
4:   dd   ff  85

# df2
col1 <- c("zz", "bb", "cc", "ff") 
col2 <- c("bb", "aa", "dd", "dd") 
y <- c(34, 567, 56, 101)
dt2 <- data.table(col1, col2, y)

    col1 col2  y
1:   zz   bb  34
2:   bb   aa 567
3:   cc   dd  56
4:   ff   dd 101

因此,col1和col2中的值对于两个数据表都是相同的,但分布是不同的。例如。 aa在dt1中的col1中,但在dt2中的col2中。 我想基于col1和col2对合并/连接数据表,但它们可能在另一个数据表中的顺序相反。 (请注意,简单地对它们进行排序并不起作用。)

这意味着合并/加入等必须能够看到&#39; dt1中的对aa + bb在dt2中以bb + aa出现并指定正确的dt2值,即所需的输出是:

   col1 col2   x   y
1:   aa   bb 130 567
2:   bb   zz  29  34
3:   cc   dd 122  56
4:   dd   ff  85 101

或者这个(即dt1或dt2的顺序是否保留并不重要):

   col1 col2   x   y
1:   zz   bb  29  34
2:   bb   aa 130 567
3:   cc   dd 122  56
4:   ff   dd  85 101

我的原始数据表大约有。 300万行(是的,它们非常庞大),所以手工做任何事都是不可能的。 我在这里环顾四周,但我找不到任何适合我案例的解决方案。有谁知道怎么做?

非常感谢任何提示!

3 个答案:

答案 0 :(得分:2)

您可以执行以下操作:

dt1[dt2, on=.(col1, col2), y:= y]

dt1[dt2, on=.(col1==col2, col2==col1), y:= i.y]

> dt1
#    col1 col2   x   y
# 1:   aa   bb 130 567
# 2:   bb   zz  29  34
# 3:   cc   dd 122  56
# 4:   dd   ff  85 101

答案 1 :(得分:1)

无法找到任何直接答案,所以尝试了下面的代码。 希望它会有所帮助

require(stringi)
require(data.table)
require(dplyr)
dt1$as <- paste(dt1$col1,dt1$col2)
dt2$as <- paste(dt2$col1,dt2$col2)
dt2$as1 <- stringi::stri_reverse(dt2$as)

f1 <- merge(dt1,dt2,by="as")
f1 <- subset(f1,select=c(2,3,4,7))
f1 <- setnames(f1,c("col1.x","col2.x"),c("Col1","Col2"))
f2 <- merge(dt1,dt2,by.x = "as",by.y = "as1")
f2 <- subset(f2,select=c(2,3,4,7))
f2 <- setnames(f2,c("col1.x","col2.x"),c("Col1","Col2"))
final <- bind_rows(f2,f1)

final
    Col1 Col2   x   y
1:   aa   bb 130 567
2:   bb   zz  29  34
3:   dd   ff  85 101
4:   cc   dd 122  56 

答案 2 :(得分:1)

所以,我们有两个有效的解决方案!

版本1: 改编自弗兰克上面的评论:

 library(dplyr)
 final <- dt2[col1 > col2, c("col1", "col2") := .(col2, col1)]
 final <- dt1[dt2, on=.(col1, col2)]
 final <- select(final, col1, col2, x, y) # select relevant columns
 final
  col1 col2   x   y
1:   bb   zz  29  34
2:   aa   bb 130 567
3:   cc   dd 122  56
4:   dd   ff  85 101

版本2:这只是对PritamJ的回答的一个调整,它简化了一些事情,使这个解决方案更适用于大型数据表。希望它也有助于其他人!

library(dplyr)
dt1$pairs <- paste(dt1$col1, dt1$col2) # creates new column with col1 and col2 
merged into one
dt2$pairs <- paste(dt2$col1, dt2$col2) # same here
dt2$revpairs <- paste(dt2$col2, dt2$col1) # creates new column with reverse pairs

f1 <- merge(dt1, dt2, by="pairs") # merge by pairs as they are in dt1
f1 <- select(f1, col1.x, col2.x, x, y) # select by name (easier for big dt) 

f2 <- merge(dt1, dt2, by.x = "pairs", by.y = "revpairs") # merge by pairs and reverse pairs
colnames(f2)[ncol(f2)] <- "revpairs" # rename last column because it has the same name as the first, which can cause errors
f2 <- select(f2, col1.x, col2.x, x, y) 


final <- bind_rows(f2, f1) # bind the two together
colnames(final)[1:2] <- c("col1", "col2") # this is not necessary, just for clarity
final
   col1 col2   x   y
1:   aa   bb 130 567
2:   bb   zz  29  34
3:   dd   ff  85 101
4:   cc   dd 122  56