R 基于匹配每个数据帧中的两个可交换列合并两个数据帧

R 基于匹配每个数据帧中的两个可交换列合并两个数据帧,r,merge,match,dataframe,R,Merge,Match,Dataframe,我在R中有两个数据帧 数据帧1 A B C D E F G 1 2 a a a a a 2 3 b b b c c 4 1 e e f f e 数据帧2 X Y Z 1 2 g 2 1 h 3 4 i 1 4 j 我想将dataframe1的A列和B列与dataframe2的X列和Y列进行匹配。这不是成对比较,即第1行(A=1 B=2)被视为与dataframe2的第1行(X=1,Y=2)和第2行(X=2,Y=1)相同 当可以找到匹配时,我想将dataframe1的C、D、E、F列添加回da

我在R中有两个数据帧

数据帧1

A B C D E F G
1 2 a a a a a
2 3 b b b c c
4 1 e e f f e
数据帧2

X Y Z
1 2 g
2 1 h
3 4 i
1 4 j
我想将dataframe1的A列和B列与dataframe2的X列和Y列进行匹配。这不是成对比较,即第1行(A=1 B=2)被视为与dataframe2的第1行(X=1,Y=2)和第2行(X=2,Y=1)相同

当可以找到匹配时,我想将dataframe1的C、D、E、F列添加回dataframe2的匹配行,如下所示:不匹配为na

最终数据帧

X Y Z C  D  E  F  G
1 2 g a  a  a  a  a 
2 1 h a  a  a  a  a
3 4 i na na na na na
1 4 j e  e  f  f  e
我只能知道如何对单个列进行匹配,但是如何对两个可交换列进行匹配,并根据匹配结果合并两个数据帧对我来说很困难。请帮忙提供一个聪明的方法

为了便于讨论(感谢Vincent和DWin(我以前的问题)的评论,我应该测试这个引用。)有将数据帧1和2加载到R的配额

df1 <- data.frame(A = c(1,2,4), B=c(2,3,1), C=c('a','b','e'), 
                                D=c('a','b','e'), E=c('a','b','f'), 
                                F=c('a','c','f'), G=c('a','c', 'e'))

df2  <- data.frame(X = c(1,2,3,1), Y=c(2,1,4,4), Z=letters[7:10])

df1以下功能可以工作,但无疑可以改进

我首先创建一个小助手函数,它对a和B执行行排序(并将其重命名为V1和V2)


这有点笨重,有一些潜在的冲突和顺序问题,但与您的示例一起使用

df1a <- df1; df1a$A <- df1$B; df1a$B <- df1$A #reverse A and B
merge(df2, rbind(df1,df1a), by.x=c("X","Y"), by.y=c("A","B"), all.x=TRUE)

df1a一种方法是为匹配创建一个顺序不变的
id

# create id key to match
require(plyr)
df1 = adply(df1, 1, transform, id = paste(min(A, B),  "-", max(A, B)))
df2 = adply(df2, 1, transform, id = paste(min(X, Y),  "-", max(X, Y)))

# combine data frames using `match`
cbind(df2, df1[match(df2$id, df1$id),3:7])
这将产生输出

X Y Z    id    C    D    E    F    G
1   1 2 g 1 - 2    a    a    a    a    a
1.1 2 1 h 1 - 2    a    a    a    a    a
NA  3 4 i 3 - 4 <NA> <NA> <NA> <NA> <NA>
3   1 4 j 1 - 4    e    e    f    f    e
X Y Z id C D E F G
1112G1-2A
1.1 2 1 h 1-2 a
na34i3-4
3 1 4 j 1-4 e f e

您还可以通过两种方式(分别是
X==A
Y==B
,然后是
X==B
Y==A
)和
rbind
将表连接起来。这将产生重复对,其中一种方法产生匹配,另一种方法产生
NA
,因此您可以通过为每个X-Y组合仅切片一行来减少重复,如果存在,则不存在
NA

library(dplyr)
m <- left_join(df2,df1,by = c("X" = "A","Y" = "B"))
n <- left_join(df2,df1,by = c("Y" = "A","X" = "B"))

rbind(m,n) %>%
  group_by(X,Y) %>%
  arrange(C,D,E,F,G) %>% # sort to put NA rows on bottom of pairs
  slice(1) # take top row from combination

在R基中还有另一种可能的解决方案。此解决方案
cbind()
使用向量化的
pmin()
pmax()
函数导出键列的规范顺序,并合并到以下两个数据帧中:

merge(cbind(df2,K1=pmin(df2$X,df2$Y),K2=pmax(df2$X,df2$Y)),cbind(df1,K1=pmin(df1$A,df1$B),K2=pmax(df1$A,df1$B)),all.x=T)[,-c(1:2,6:7)];
##   X Y Z    C    D    E    F    G
## 1 1 2 g    a    a    a    a    a
## 2 2 1 h    a    a    a    a    a
## 3 1 4 j    e    e    f    f    e
## 4 3 4 i <NA> <NA> <NA> <NA> <NA>
merge(cbind(df2,K1=pmin(df2$X,df2$Y),K2=pmax(df2$X,df2$Y)),cbind(df1,K1=pmin(df1$A,df1$B),K2=pmax(df1$A,df1$B)),all.X=T[,-c(1:2,6:7)];
##X Y Z C D E F G
##1 1 2 g a a a a a
##2 2 1小时a
##3 1 4 j e f e
##4 3 4 i

请注意,使用
pmin()
pmax()
只能解决此问题,因为您只有两个键列;如果有更多,则必须使用某种“应用+排序”解决方案来实现合并的规范键顺序,类似于@Andrie在其helper函数中所做的,该函数适用于任意数量的键列,但性能较差。

如何处理冲突?也就是说,当df1的行中有X=1和Y=2以及X=2和Y=1时?你能保证那不会发生吗?
X Y Z    id    C    D    E    F    G
1   1 2 g 1 - 2    a    a    a    a    a
1.1 2 1 h 1 - 2    a    a    a    a    a
NA  3 4 i 3 - 4 <NA> <NA> <NA> <NA> <NA>
3   1 4 j 1 - 4    e    e    f    f    e
library(dplyr)
m <- left_join(df2,df1,by = c("X" = "A","Y" = "B"))
n <- left_join(df2,df1,by = c("Y" = "A","X" = "B"))

rbind(m,n) %>%
  group_by(X,Y) %>%
  arrange(C,D,E,F,G) %>% # sort to put NA rows on bottom of pairs
  slice(1) # take top row from combination
Source: local data frame [4 x 8]
Groups: X, Y

  X Y Z  C  D  E  F  G
1 1 2 g  a  a  a  a  a
2 1 4 j  e  e  f  f  e
3 2 1 h  a  a  a  a  a
4 3 4 i NA NA NA NA NA
merge(cbind(df2,K1=pmin(df2$X,df2$Y),K2=pmax(df2$X,df2$Y)),cbind(df1,K1=pmin(df1$A,df1$B),K2=pmax(df1$A,df1$B)),all.x=T)[,-c(1:2,6:7)];
##   X Y Z    C    D    E    F    G
## 1 1 2 g    a    a    a    a    a
## 2 2 1 h    a    a    a    a    a
## 3 1 4 j    e    e    f    f    e
## 4 3 4 i <NA> <NA> <NA> <NA> <NA>