2011-05-25 98 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在其輔助函數中執行的操作,這對於任何數量的關鍵列都有效,但性能會降低。

相關問題