将一个数据框中的两列与另一个数据框中的两列匹配,与顺序无关

时间:2018-02-18 16:13:04

标签: r bioinformatics

以两个数据帧为例:

<ng-template>

如何创建新的df1 = data.frame(V1 = c('JOHN', 'BRIAN','KATE', 'ERIC', 'CURT', 'ZACH'), V2 = c('ABIGAIL', 'ANDY', 'GEORGE', 'JOHN', 'MARY', 'FRANKLIN'), V3 = seq(1,6,1), V4 = seq(1,6,1)) df2 = data.frame(V1 = c('ABIGAIL', 'BRIAN','KATE', 'ERIC'), V2 = c('JOHN', 'ANDY', 'MARTIN', 'ANDREW')) df1 V1 V2 V3 V4 JOHN ABIGAIL 1 1 BRIAN ANDY 2 2 KATE GEORGE 3 3 ERIC JOHN 4 4 CURT MARY 5 5 ZACH FRANKLIN 6 6 df2 V1 V2 ABIGAIL JOHN BRIAN ANDY KATE MARTIN ERIC ANDREW ,其中包含df3V1中列V2df1之间匹配的行。挑战在于我希望这个匹配与订单无关。

因此示例中的df2将如下所示:

df3

我尝试过使用match()和%in%运算符而没有任何运气。

我正在寻找适用于数千行数据框架的解决方案。

修改

这两个答案都为我的问题提供了有效的解决方案。事实证明我错过了一些让它适用于我自己的数据的东西。取而代之的是数据框:

  df3
  V1   V2 V3 V4
  ABIGAIL JOHN 1 1
  BRIAN ANDY  2  2

现在我也想提取行,即使它们之间的匹配不在同一行。 df1 = data.frame(V1 = c('JOHN', 'BRIAN','KATE', 'ERIC', 'CURT', 'ZACH'), V2 = c('ABIGAIL', 'ANDY', 'GEORGE', 'JOHN', 'MARY', 'FRANKLIN'), V3 = seq(1,6,1), V4 = seq(1,6,1)) df2 = data.frame(V1 = c('ABIGAIL', 'BRIAN','KATE', 'BRIAN', 'ERIC'), V2 = c('JOHN', 'ANDY', 'MARTIN', 'ANDY', 'ANDREW')) 看起来像是:

df3

基本上我希望df3 V1 V2 V3 V4 ABIGAIL JOHN 1 1 BRIAN ANDY 2 2 BRIAN ANDY 2 2 中的V3V4中的值对df1V1中的名称之间的每次互动都有所不同。< / p>

3 个答案:

答案 0 :(得分:3)

通过使用 pmin pmax 对行V1和V2进行排序来创建ID,以便"A" "B""B" "A"具有相同的ID "A_B"。然后按ID使用 merge

df1$ID <- paste(pmin(as.character(df1$V1), as.character(df1$V2)),
                pmax(as.character(df1$V1), as.character(df1$V2)), sep = "_")

df2$ID <- paste(pmin(as.character(df2$V1), as.character(df2$V2)),
                pmax(as.character(df2$V1), as.character(df2$V2)), sep = "_")

merge(df1, df2[, "ID", drop = FALSE], by = "ID")

#             ID    V1      V2 V3 V4
# 1 ABIGAIL_JOHN  JOHN ABIGAIL  1  1
# 2   ANDY_BRIAN BRIAN    ANDY  2  2
# 3   ANDY_BRIAN BRIAN    ANDY  2  2

答案 1 :(得分:2)

library(combinat)
df1[apply(df1[,1:2], 1, paste, collapse = ' ') %in%
    apply(df2[,1:2], 1, function(x) sapply(permn(x), paste, collapse = ' '))
    ,]

使用sqldf如下所示更快,但对于&gt;而言并不容易2个变量,因为所有可能性必须在连接条件中列出。

library(sqldf)
sqldf('
select  df1.*
from    df1
        inner join df2
            on  (df1.V1 = df2.V1 and df1.V2 = df2.V2)
                or (df1.V1 = df2.V2 and df1.V2 = df2.V1)
')

答案 2 :(得分:2)

你不需要包裹;只需测试两种方式:

## Make a frame with combined in both ways
df1o = data.frame(V12 =paste(df1$V1,df1$V2, sep="-"), V21= paste(df1$V2,df1$V1, sep="-"))
## Make a frame with the second combination
df2o = data.frame(P =paste(df2$V1,df2$V2, sep="-") )
## Compare the combinations in both ways and select those that match in a new df
df3 = df1[which(df1o$V12 %in% df2o$P | df1o$V21 %in% df2o$P),]
df3

结果

> df3
     V1      V2 V3 V4
1  JOHN ABIGAIL  1  1
2 BRIAN    ANDY  2  2Z