R 基于匹配每个数据帧中的两个可交换列合并两个数据帧
我在R中有两个数据帧 数据帧1R 基于匹配每个数据帧中的两个可交换列合并两个数据帧,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
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>