将一个数据框中的两列与另一个数据框中的两列进行匹配,与顺序无关
Matching two columns in one data frame against two columns in another, independently of the order
以两个数据框为例:
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
我如何创建一个新的 df3
,其中包含在 df1
和 df2
中的 V1
和 V2
列之间匹配的行。挑战在于我希望这场比赛与顺序无关。
因此 df3
在示例中看起来像:
df3
V1 V2 V3 V4
ABIGAIL JOHN 1 1
BRIAN ANDY 2 2
我尝试过使用 match() 和 %in% 运算符,但没有成功。
我正在寻找适用于具有数千行的数据框的解决方案。
编辑
这两个答案都为我的问题提供了可行的解决方案。事实证明我错过了一些使其适用于我自己的数据的东西。取而代之的是数据框:
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
基本上,我希望 df1
中的 V3
和 V4
中的值适用于 V1
和 V2
中的名称之间的每个交互独立于顺序.
library(combinat)
df1[apply(df1[,1:2], 1, paste, collapse = ' ') %in%
apply(df2[,1:2], 1, function(x) sapply(permn(x), paste, collapse = ' '))
,]
使用如下所示的 sqldf
速度更快,但对于 > 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)
')
您不需要包裹;只需测试两种方式:
## 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
通过使用 pmin 和 pmax 对 V1 和 V2 列按行排序来创建 ID,以便 "A" "B"
和 "B" "A"
将具有与 "A_B"
相同的 ID。然后通过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
以两个数据框为例:
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
我如何创建一个新的 df3
,其中包含在 df1
和 df2
中的 V1
和 V2
列之间匹配的行。挑战在于我希望这场比赛与顺序无关。
因此 df3
在示例中看起来像:
df3
V1 V2 V3 V4
ABIGAIL JOHN 1 1
BRIAN ANDY 2 2
我尝试过使用 match() 和 %in% 运算符,但没有成功。
我正在寻找适用于具有数千行的数据框的解决方案。
编辑
这两个答案都为我的问题提供了可行的解决方案。事实证明我错过了一些使其适用于我自己的数据的东西。取而代之的是数据框:
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
基本上,我希望 df1
中的 V3
和 V4
中的值适用于 V1
和 V2
中的名称之间的每个交互独立于顺序.
library(combinat)
df1[apply(df1[,1:2], 1, paste, collapse = ' ') %in%
apply(df2[,1:2], 1, function(x) sapply(permn(x), paste, collapse = ' '))
,]
使用如下所示的 sqldf
速度更快,但对于 > 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)
')
您不需要包裹;只需测试两种方式:
## 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
通过使用 pmin 和 pmax 对 V1 和 V2 列按行排序来创建 ID,以便 "A" "B"
和 "B" "A"
将具有与 "A_B"
相同的 ID。然后通过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