R语言如何校验两个dataframe的姓名+ID双列组合是否匹配
R实现双字段组合约束的匹配校验
测试数据构造
现有两个数据框,结构如下:
- 数据框A(待校验表)
name <- c("John", "Bill", "Amy", "Bill", "Mia") Present.ID <- c(12345, 678910, 12345, 8090100, 246810) A <- as.data.frame(cbind(name, Present.ID))
- 数据框B(参照表)
name <- c("John", "Bill", "Amy", "Bill", "Mia") Applied.ID <- c(12345, 678910, 12345, 8090100, NA) B <- as.data.frame(cbind(name, Applied.ID))
校验规则
- 核心逻辑:A中
name+Present.ID的二元组合,必须在B中存在对应的name+Applied.ID组合 - 业务约束:
- 不存在重名的不同用户,同名出现代表同一用户不同时期对应不同ID
- 不同姓名可共享同一ID
- 数据中存在大量未分配ID(值为NA)的记录
- 输出要求:在A中新增
check布尔列,标记匹配结果,效果类似单值匹配语句A$Present.ID %in% B$Applied.ID,仅额外增加姓名必须一致的约束,期望输出如下:
name Present.ID check 1 John 12345 TRUE 2 Bill 678910 TRUE 3 Amy 12345 TRUE 4 Bill 8090100 TRUE 5 Mia 246810 FALSE
实现方案
方案1:基础R无依赖实现
和单值%in%逻辑完全对齐,通过拼接组合键实现匹配,无需安装第三方包:
# 用不会出现在姓名/ID中的特殊字符串作为分隔符拼接两个字段,生成唯一组合键 A$check <- paste(A$name, A$Present.ID, sep = "___") %in% paste(B$name, B$Applied.ID, sep = "___")
注意:必须加分隔符,避免无分隔拼接时出现歧义(例如name="ab"、ID="c"和name="a"、ID="bc"会被误判为同一组合)。如果需要把A中ID为空的记录标记为无需校验,可改写为
A$check <- ifelse(is.na(A$Present.ID), NA, paste(A$name, A$Present.ID, sep = "___") %in% paste(B$name, B$Applied.ID, sep = "___"))。
方案2:dplyr连接实现(适合tidyverse工作流)
如果日常用dplyr处理数据,可通过双字段连接打标记,不需要拼接字符串,无分隔符歧义风险:
library(dplyr) A <- B %>% # 给参照表B先加匹配成功标记 mutate(check = TRUE) %>% # 双字段右连接到待校验表A right_join(A, by = c("name" = "name", "Applied.ID" = "Present.ID")) %>% # 未匹配到的记录标记为FALSE mutate(check = replace(check, is.na(check), FALSE))
两种方案返回的结果完全一致,均符合输出要求。
内容的提问来源于stack exchange,提问作者TRS6
相关产品推荐
相关产品推荐

