2011-05-25 99 views
6

我有两个数据帧中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)被认为与行1(X = 1,Y = 2)和行2(X = 2,Y = 1)数据帧2.

当找到匹配项时,我想将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 

我只能知道该怎么做了单列匹配,但是,怎么做匹配了两个可交换列和基于匹配结果合并两个dataframes对我来说很难。请帮助提供这样做的聪明方式。

为了便于讨论(感谢文森特和迪文(我以前quesiton我应该测试报价评论))。有加载数据框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]) 
+1

你如何处理碰撞?即,当df1在行中有X = 1和Y = 2且X = 2且Y = 1时?你保证不会发生? – mcpeterson 2011-05-25 07:04:38

回答

6

以下工作,但无疑可以改善。

我首先创建一个辅助函数,对A和B执行逐行排序(并将其重命名为V1和V2)。

replace_index <- function(dat){ 
    x <- as.data.frame(t(sapply(seq_len(nrow(dat)), 
    function(i)sort(unlist(dat[i, 1:2]))))) 
    names(x) <- paste("V", seq_len(ncol(x)), sep="") 
    data.frame(x, dat[, -(1:2), drop=FALSE]) 
} 

replace_index(df1) 

    V1 V2 C D E F G 
1 1 2 a a a a a 
2 2 3 b b b c c 
3 1 4 e e f f e 

这意味着您可以使用简单的merge来合并数据。

merge(replace_index(df1), replace_index(df2), all.y=TRUE) 

    V1 V2 C D E F G Z 
1 1 2 a a a a a g 
2 1 2 a a a a a h 
3 1 4 e e f f e j 
4 3 4 <NA> <NA> <NA> <NA> <NA> i 
1

这是稍微笨重,并且有一些潜在的冲突和秩序问题,而是你的榜样工程

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) 

生产

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> 
1

一种方法是创建一个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 
0

你也可以加入表两种方式(X == AY == B,然后X == BY == 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 

产地:

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 
0

下面是在基R.另一个可能的解决方案将该溶液cbind()新键列(K1K2)使用矢量pmin()pmax()函数来导出两个data.frames键列的标准顺序,并合并在那些上:

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> 

请注意,使用pmin()pmax()仅适用于此问题,因为您只有两个关键列;如果你有更多的,那么你必须使用某种应用+排序解决方案来实现合并的规范键顺序,类似于@Andrie在其辅助函数中执行的操作,这对于任何数量的关键列都有效,但性能会降低。

相关问题