r - 多列上的高效条件连接
r - Efficient conditional join on multiple columns
我有两个表,我想使用多列连接,使用 dplyr
连接函数完全可行。复杂的原因是我需要加入多个列,如果至少有一个列加入成功,则加入应该成功。为了证明我的情况,这里有一个可重现的例子:
df1 <- data.frame(
A1 = c(1,2,3,4),
B1 = c(4,5,6,7),
C1 = c("a", "b", "c", "d")
)
df2 <- data.frame(
A2 = c(8,"",3,4),
B2 = c(9,5,"",7),
C2 = c("aa", "bb", "cc", "dd")
)
我想在 A 列 或 B 上加入 df1
和 df2
,这意味着保留至少 df1$A = df2 的所有行$A 或 df1$B = df2$B(请注意我的真实数据集有 6 列我想用于连接)。简化示例的最终结果应为:
data.frame(
A1 = c(2,3,4),
A2 = c("",3,7),
B1 = c(5,6,7),
B2 = c(5,"", 7),
C1 = c("b", "c", "d"),
C2 = c("bb", "cc", "dd")
)
非常感谢有关如何有效完成此操作的任何建议,或者如果无法快速完成,那么也可以接受慢速解决方案
不太确定如何使用 dplyr
执行此操作,但 sqldf
可以帮助您:
library(sqldf)
sqldf("SELECT *
FROM df1
JOIN df2
ON df1.A1 = df2.A2
OR df1.B1 = df2.B2")
您可以在此之后为更多列添加额外的 OR 语句。
这似乎不可能通过一次调用 dplyr
连接函数实现。
如果您想使用 dplyr
连接,这是我使用 purrr
映射函数创建的一个 hacky 解决方法,为条件连接中的每个条件执行单独的内部连接.然后将它们绑定在一起并删除重复的行。它可以通过附加到 key1
和 key2
向量来泛化到更多列。
注意:首先我们需要修改示例数据,使要连接的列具有相同的类型。如果您尝试连接不兼容的列类型,dplyr
会引发错误,在本例中为整数和字符。
library(dplyr)
library(purrr)
df1 <- df1 %>%
mutate(A1 = as.character(A1), B1 = as.character(B1))
key1 <- c('A1', 'B1')
key2 <- c('A2', 'B2')
map2_dfr(key1, key2, ~ inner_join(df1, df2, by = setNames(.y, .x), keep = TRUE)) %>%
distinct()
结果:
A1 B1 C1 A2 B2 C2
1 3 6 c 3 cc
2 4 7 d 4 7 dd
3 2 5 b 5 bb
一个简单的方法可以是:
library(dplyr)
df1 <- df1 %>%
mutate(A1 = as.character(A1), B1 = as.character(B1))
df1 %>%
bind_cols(df2) %>%
filter(A1 == A2 | B1 == B2) %>%
relocate(sort(names(.)))
#> A1 A2 B1 B2 C1 C2
#> 1 2 5 5 b bb
#> 2 3 3 6 c cc
#> 3 4 4 7 7 d dd
我有两个表,我想使用多列连接,使用 dplyr
连接函数完全可行。复杂的原因是我需要加入多个列,如果至少有一个列加入成功,则加入应该成功。为了证明我的情况,这里有一个可重现的例子:
df1 <- data.frame(
A1 = c(1,2,3,4),
B1 = c(4,5,6,7),
C1 = c("a", "b", "c", "d")
)
df2 <- data.frame(
A2 = c(8,"",3,4),
B2 = c(9,5,"",7),
C2 = c("aa", "bb", "cc", "dd")
)
我想在 A 列 或 B 上加入 df1
和 df2
,这意味着保留至少 df1$A = df2 的所有行$A 或 df1$B = df2$B(请注意我的真实数据集有 6 列我想用于连接)。简化示例的最终结果应为:
data.frame(
A1 = c(2,3,4),
A2 = c("",3,7),
B1 = c(5,6,7),
B2 = c(5,"", 7),
C1 = c("b", "c", "d"),
C2 = c("bb", "cc", "dd")
)
非常感谢有关如何有效完成此操作的任何建议,或者如果无法快速完成,那么也可以接受慢速解决方案
不太确定如何使用 dplyr
执行此操作,但 sqldf
可以帮助您:
library(sqldf)
sqldf("SELECT *
FROM df1
JOIN df2
ON df1.A1 = df2.A2
OR df1.B1 = df2.B2")
您可以在此之后为更多列添加额外的 OR 语句。
这似乎不可能通过一次调用 dplyr
连接函数实现。
如果您想使用 dplyr
连接,这是我使用 purrr
映射函数创建的一个 hacky 解决方法,为条件连接中的每个条件执行单独的内部连接.然后将它们绑定在一起并删除重复的行。它可以通过附加到 key1
和 key2
向量来泛化到更多列。
注意:首先我们需要修改示例数据,使要连接的列具有相同的类型。如果您尝试连接不兼容的列类型,dplyr
会引发错误,在本例中为整数和字符。
library(dplyr)
library(purrr)
df1 <- df1 %>%
mutate(A1 = as.character(A1), B1 = as.character(B1))
key1 <- c('A1', 'B1')
key2 <- c('A2', 'B2')
map2_dfr(key1, key2, ~ inner_join(df1, df2, by = setNames(.y, .x), keep = TRUE)) %>%
distinct()
结果:
A1 B1 C1 A2 B2 C2
1 3 6 c 3 cc
2 4 7 d 4 7 dd
3 2 5 b 5 bb
一个简单的方法可以是:
library(dplyr)
df1 <- df1 %>%
mutate(A1 = as.character(A1), B1 = as.character(B1))
df1 %>%
bind_cols(df2) %>%
filter(A1 == A2 | B1 == B2) %>%
relocate(sort(names(.)))
#> A1 A2 B1 B2 C1 C2
#> 1 2 5 5 b bb
#> 2 3 3 6 c cc
#> 3 4 4 7 7 d dd