使用可变列连接表 - dplyr, r, join

Joining tables using variable columns - dplyr, r, join

问题: 我有 2 个表要加入。但是,我希望将第二个连接到第一个的列会有所不同,具体取决于对第二个数据框的成功解析以确定要连接的列和行。

请求: 我找到了解决问题的方法(见下文),但在我看来它的计算效率并不高。对于下面的可重现示例来说不是问题,但在涉及更大规模的问题时可能不太理想,即 ~200,000+ 行/观察。

想知道是否有人可以帮助识别更好的东西 - 最好利用 dplyr 的功能。

可重现示例:

# Equipment alias table
alias1    <- c('a1a1', 'a2a2', 'a3a3', 'a4a4', 'a5a5', 'a6a6')
alias2   <- c('bc001', 'bc002', 'bc003', 'bc004', 'bc005', 'bc006')
alias3   <- c('e1o1', 'e202', 'e303', 'e404', 'e505', 'e606')

df_alias <- data.frame(alias1, alias2, alias3)

# Attribute table
equip    <- c('a1a1','bc006', 'e404')
att1     <- c('a', 'b', 'c')
att2     <- c('1', '2', '3')

df_att   <- data.frame(equip, att1, att2)

期望的结果:

我希望实现以下目标....

# DESRIED OUTPUT - combining equipment alias table into attribute table based on string match between attibute_equip and any one of columns in equipment alias
equip    <- c('a1a1','bc006', 'e404')
att1     <- c('a', 'b', 'c')
att2     <- c('1', '2', '3')
alias1   <- c('a1a1','a6a6', 'a4a4')
alias2   <- c('bc001','bc006', 'bc004')
alias3   <- c('e1o1','e606', 'e404')

df_att   <- data.frame(equip, att1, att2, alias1, alias2, alias3)

当前解:

library(dplyr)  
left_join(df_att, df_alias, by = character()) %>% 
filter(equip == alias1 | equip == alias2 | equip == alias3)

有效但不完全优雅,因为存在大量重复,最终要应用过滤器来撤消重复。

一个选项是 filterif_any,然后将子集行与 df_att

绑定
library(dplyr)
df_att2 <- df_alias %>%
    filter(if_any(everything(), ~ .x %in% df_att$equip)) %>% 
    arrange(na.omit(unlist(across(everything(), ~ match(df_att$equip, .x))))) %>% 
    bind_cols(df_att, .)

-检查 OP 的预期(将对象名称 'df_att' 更改为 'out' 以避免混淆)

> all.equal(df_att2, out)
[1] TRUE

我不知道它如何与 efficiency-wise 进行比较,但一个想法是旋转每个别名的副本,以便您可以 left_join 针对单个列而不是多个列。

library(tidyr)
library(dplyr)

df_alias %>% 
  mutate(across(everything(), ~., .names = "_{.col}")) %>% 
  pivot_longer(starts_with('_'), names_to = NULL, values_to = 'equip') %>% 
  left_join(df_att, .)

#> Joining, by = "equip"
#>   equip att1 att2 alias1 alias2 alias3
#> 1  a1a1    a    1   a1a1  bc001   e1o1
#> 2 bc006    b    2   a6a6  bc006   e606
#> 3  e404    c    3   a4a4  bc004   e404