R语言:如何基于多列匹配直接左连接两个数据框(无需两次连接)
问题描述
现有两个R数据框df1和df2,数据定义及输出如下:
df1 <- data.frame(col1 = c("a", "c", "d"), col2 = c("m", "e", "d")) # df1 输出 col1 col2 1 a m 2 c e 3 d d
df2 <- data.frame(coll1 = c("m", "f", "d"), coll2 = c(2, 4, 5)) # df2 输出 coll1 coll2 1 m 2 2 f 4 3 d 5
需求是:无需执行两次左连接,直接基于df1的col1或col2与df2的coll1匹配的条件完成左连接,最终得到如下结果:
# 第一行:df1的"a"和"m"中,"m"匹配df2的coll1,对应值为2 # 第二行:df1的"c"和"e"均无匹配项,对应值为NA # 第三行:"d"同时匹配两列,对应值为5 df3 col1 col2 output 1 a m 2 2 c e NA 3 d d 5
解决方案
方法1:dplyr(tidyverse)实现
先逐行提取df1中能匹配df2$coll1的第一个值,再做一次左连接,最后整理结果:
library(dplyr) df3 <- df1 %>% # 逐行获取col1/col2中第一个匹配df2$coll1的值,无匹配则为NA mutate(match_val = pmap_chr(across(c(col1, col2)), ~ { vals <- c(..1, ..2) hits <- vals[vals %in% df2$coll1] if (length(hits) > 0) hits[1] else NA_character_ })) %>% # 左连接df2,匹配match_val和coll1 left_join(df2, by = c("match_val" = "coll1")) %>% # 重命名并保留需要的列 rename(output = coll2) %>% select(col1, col2, output)
方法2:Base R 原生实现
用apply逐行处理匹配逻辑,再通过match映射对应值:
# 逐行提取df1中第一个匹配df2$coll1的值 match_vals <- apply(df1, 1, function(row) { hits <- row[row %in% df2$coll1] if (length(hits) > 0) hits[1] else NA }) # 映射df2中对应的coll2值 output <- df2$coll2[match(match_vals, df2$coll1)] # 组合成结果数据框 df3 <- cbind(df1, output = output)
方法3:data.table(大数据场景高效)
如果数据量较大,data.table的逐行处理和连接效率更高:
library(data.table) setDT(df1) setDT(df2) df3 <- df1[, match_val := { vals <- c(col1, col2) hits <- vals[vals %in% df2$coll1] if (length(hits) > 0) hits[1] else NA_character_ }, by = .I][ # .I 代表逐行处理 df2, on = .(match_val = coll1), output := i.coll2 ][, .(col1, col2, output)] # 保留目标列
内容的提问来源于stack exchange,提问作者islem
相关产品推荐
相关产品推荐

