高效实现R中双条件匹配合并DataFrame并添加PID字段
高效匹配DataFrame并填充PID的解决方案
问题背景
现有两个DataFrame:df.old(包含PID、姓名、邮箱字段)和df.new(包含邮箱、姓名字段),需要将df.old中的PID匹配填充到df.new中,匹配规则为:
- 优先通过邮箱进行匹配
- 邮箱为空或匹配失败时,使用
firstname与lastname的拼接值(paste(firstname, lastname))匹配
此前使用自定义查找函数(如get_PID_by_mail、get_PID_by_name)矢量化处理,大数据量下效率偏低,需更高效的实现方案。
示例数据
df.old <- data.frame(PID = c(1, 2, 3, 4, NA), firstname = c("", "Peter", "David", "Jessy", ""), lastname = c("", "White", "Smith", "Connor", ""), mail = c("user1@mail.com", "user2@mail.com", NA, "user10@mail.com", NA)) df.new <- data.frame(mail = c("user1@mail.com", "user2@mail.com", NA, NA , NA), firstname = c("", "", "", "David", ""), lastname = c("", "", "", "Smith", ""))
高效解决方案
推荐使用dplyr或data.table的连接操作,二者均针对大数据量做了性能优化,远快于自定义循环/函数。
方法1:用dplyr分步连接
核心逻辑是先完成邮箱匹配,再对未匹配成功的行用姓名拼接补全:
library(dplyr) # 预处理df.old:生成姓名拼接列,过滤无效匹配项 df.old_processed <- df.old %>% mutate(full_name = paste(firstname, lastname, sep = " ")) %>% filter(!is.na(PID)) %>% # 过滤无有效PID的行 filter(!(is.na(mail) & full_name == " ")) # 过滤无有效匹配键的行 # 第一步:按邮箱左连接,得到初始PID df.new_result <- df.new %>% left_join(df.old_processed %>% select(mail, PID), by = "mail") %>% mutate(full_name = paste(firstname, lastname, sep = " ")) # 第二步:对邮箱匹配失败的行,用姓名拼接补全PID df.new_result <- df.new_result %>% left_join(df.old_processed %>% select(full_name, PID), by = "full_name", suffix = c("", "_name")) %>% mutate(PID = ifelse(is.na(PID), PID_name, PID)) %>% # 优先保留邮箱匹配结果 select(-full_name, -PID_name) # 清理临时列 # 查看最终结果 df.new_result
方法2:用data.table(超大数据量首选)
data.table的连接操作性能优于dplyr,适合百万级以上规模的数据:
library(data.table) # 转换为data.table格式 setDT(df.old) setDT(df.new) # 预处理df.old:生成姓名拼接列,过滤无效行 df.old[, full_name := paste(firstname, lastname, sep = " ")] df.old_processed <- df.old[!is.na(PID) & !(is.na(mail) & full_name == " ")] # 第一步:按邮箱匹配PID df.new[, PID := df.old_processed[.SD, on = "mail", x.PID]] # 第二步:对未匹配到PID的行,用姓名拼接补全 df.new[is.na(PID), PID := df.old_processed[.SD, on = "full_name", x.PID]] # 查看最终结果 df.new
预期输出
mail firstname lastname PID 1: user1@mail.com 1 2: user2@mail.com 2 3: <NA> NA 4: <NA> David Smith 3 5: <NA> NA
内容的提问来源于stack exchange,提问作者D. Studer
相关产品推荐
相关产品推荐

