R dplyr连接两表时保留异名匹配列、丢弃同名重复列的方法
问题描述
使用dplyr::left_join()做两表连接时,需要同时使用两类列作为连接键:
- 两表中名称完全相同的列
- 两表中名称不一致的列
期望输出规则:
- 两表中名称不同的连接列全部保留
- 同名连接列仅保留1份,不生成重复列
现有方案存在明显缺陷:
- 默认参数下,异名匹配的右表连接列会被直接丢弃
- 设置
keep = TRUE时,同名连接列会生成带后缀的重复列,无法自动区分保留/丢弃规则
问题复现代码
# 示例:默认参数连接,carb列被丢弃 dplyr::left_join( dplyr::select(head(mtcars), vs, am, gear), dplyr::select(tail(mtcars), vs, am, carb, qsec), by = c("vs", "am", "gear" = "carb")) #> vs am gear qsec #> 1 0 1 4 14.5 #> 2 0 1 4 14.5 #> 3 1 1 4 NA #> 4 1 0 3 NA #> 5 0 0 3 NA #> 6 1 0 3 NA # 非目标方案:设置keep=TRUE,同名列产生重复 dplyr::left_join( dplyr::select(head(mtcars), vs, am, gear), dplyr::select(tail(mtcars), vs, am, carb, qsec), by = c("vs", "am", "gear" = "carb"), keep = TRUE) #> vs.x am.x gear vs.y am.y carb qsec #> 1 0 1 4 0 1 4 14.5 #> 2 0 1 4 0 1 4 14.5 #> 3 1 1 4 NA NA NA NA #> 4 1 0 3 NA NA NA NA #> 5 0 0 3 NA NA NA NA #> 6 1 0 3 NA NA NA NA
预期输出
#> vs am gear carb qsec #> 1 0 1 4 4 14.5 #> 2 0 1 4 4 14.5 #> 3 1 1 4 NA NA #> 4 1 0 3 NA NA #> 5 0 0 3 NA NA #> 6 1 0 3 NA NA
目前的临时实现方式是设置suffix = c("", ".y"),连接完成后再删除带.y后缀的重复列,但需要额外执行列选择步骤:
library(magrittr) dplyr::left_join( dplyr::select(head(mtcars), vs, am, gear), dplyr::select(tail(mtcars), vs, am, carb, qsec), by = c("vs", "am", "gear" = "carb"), keep = TRUE, suffix = c("", ".y")) %>% dplyr::select(!dplyr::ends_with(".y"))
示例创建于2022-06-22,基于reprex包(v2.0.1)生成
解决方案
不需要额外的select步骤,直接把by参数里的所有连接键都写成"左表列名" = "右表列名"的完整命名向量格式即可,代码如下:
dplyr::left_join( dplyr::select(head(mtcars), vs, am, gear), dplyr::select(tail(mtcars), vs, am, carb, qsec), by = c("vs" = "vs", "am" = "am", "gear" = "carb") )
运行结果和预期完全一致,没有重复列,也没有丢失异名连接键。
原理说明
这是dplyrby参数的内置处理规则:
- 如果传入无名字符串(比如直接写
"vs")属于简写形式,默认按「两表同名列匹配,仅保留左表列」处理,异名匹配的右表连接列会被直接丢弃 - 如果全部传入命名向量格式的键值对,dplyr会逐对判断左右列名:左右列名一致就只保留一份列,列名不一致就自动把两列都保留在结果中,完全匹配需求的保留规则,不需要额外的后缀处理和列筛选操作。
内容的提问来源于stack exchange,提问作者Paul
相关产品推荐
相关产品推荐

