如何使用dplyr的left_join合并含基因与MeSH ID的两个数据框
实现方案
原代码错误原因
你之前的写法存在两个核心问题:
left_join的多条件匹配默认是同时满足所有条件,无法实现你需要的「匹配Parent.MeSH.ID或Child.MeSH.ID」的逻辑- df2的
Parent.MeSH.ID、Child.MeSH.ID是逗号分隔的多值字符串,直接等值匹配只能命中单值的情况,多值场景会全部匹配失败
推荐实现(纯tidyverse生态,无需额外安装包)
该方案会保留df2中原始的逗号分隔ID格式,符合你的使用需求:
# 加载依赖包 library(dplyr) library(tidyr) # 第一步:给df2添加唯一行标识,用于匹配后关联回原始行 df2_with_rowid <- df2 %>% mutate(rowid = row_number()) # 第二步:拆分df2的多值ID列为单值行,生成匹配映射表 df2_match_map <- df2_with_rowid %>% # 按逗号+任意空格拆分多ID为单独行 separate_rows(Parent.MeSH.ID, Child.MeSH.ID, sep = ",\\s*") %>% # 合并两类MeSH ID为统一匹配列 pivot_longer(cols = c(Parent.MeSH.ID, Child.MeSH.ID), values_to = "match_id") %>% # 去重,避免重复匹配 distinct(rowid, Gene.Name, match_id) # 第三步:执行匹配,得到最终结果 proto <- df1 %>% # 匹配基因名和MeSH ID,用inner_join直接过滤未匹配行 inner_join(df2_match_map, by = c("HUGO_symbol" = "Gene.Name", "MeSH_ID" = "match_id")) %>% # 关联回df2的原始完整数据 left_join(df2_with_rowid, by = c("rowid", "HUGO_symbol" = "Gene.Name")) %>% # 去除辅助列,去重避免重复行 select(-rowid, -name) %>% distinct()
简洁实现(用fuzzyjoin包)
如果接受安装额外包,可以用正则匹配的方式更简洁实现:
library(dplyr) library(fuzzyjoin) library(stringr) proto <- df1 %>% fuzzy_inner_join( df2, # 自定义匹配规则:基因名相等,且MeSH ID存在于Parent或Child ID列表中 match_fun = list( `==`, \(mesh_id, id_list) str_detect(id_list, paste0("(^|,\\s*)", mesh_id, "($|,\\s*)")) ), by = c( "HUGO_symbol" = "Gene.Name", "MeSH_ID" = "Parent.MeSH.ID", "MeSH_ID" = "Child.MeSH.ID" ) )
内容的提问来源于stack exchange,提问作者KLM117
相关产品推荐
相关产品推荐

