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

时间:2011-05-25 05:34:32

标签: r merge match dataframe

我在R中有两个数据框。

dataframe 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

dataframe 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的第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])

5 个答案:

答案 0 :(得分: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 :(得分: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>

答案 2 :(得分: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

答案 3 :(得分:0)

您也可以双向加入表格(X == AY == B,然后加入X == BY == A)和rbind。这将生成重复对,其中一种方式产生匹配而另一种方式产生NA,因此您可以通过为每个XY组合切片仅一行来减少重复,如果存在,则不包括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

答案 4 :(得分:0)

以下是基础R中的另一种可能解决方案。此解决方案使用向量化cbind()和{K1个新的关键列(K2pmin())到两个data.frames {1}}函数用于派生键列的规范顺序,并合并到那些:

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> pmin()的使用仅适用于此问题,因为您只有两个关键列;如果你有更多,那么你必须使用某种apply + sort解决方案来实现合并的规范键顺序,类似于@Andrie在他的帮助函数中所做的,这对任意数量的键列都有效,但是性能会降低。