如何在dplyr中按字符串变量匹配完成left_join并生成判断标识?
问题描述
现有两个数据框primary和secondary:
library(dplyr) primary <- data.frame( id = c("A123", "B456", "C789", "D012"), prod = c("1111", "2222", "3333", "4444"), d= c("USA", "CAN", "MEX", "BRA") ) secondary <- data.frame( id= c("A123", "B456", "C789", "D012"), prod= c("1111", "2222", "3333", "4444"), rec_d = c("USA", "CAN,MEX", NA, "BRA") )
需要通过id和prod字段对两个数据框执行left_join,同时判断primary中的d值是否存在于secondary的rec_d(逗号分隔的字符串)中,生成flag标识(符合条件为1,否则为0)。
尝试的代码未成功:
result <- left_join(primary, secondary, by = c("id", "prod")) %>% mutate(flag = ifelse(d %in% rec_d| is.na(rec_d), 1, 0))
期望输出:
desired <- structure(list(id = c("A123", "B456", "C789", "D012"), prod = c("1111", "2222", "3333", "4444"), d = c("USA", "CAN", "MEX", "BRA"), rec_d = c("USA", "CAN,MEX", NA, "BRA"), flag = c(1, 1, 0, 1)), class = "data.frame", row.names = c(NA, -4L))
问题原因
d %in% rec_d逻辑错误:rec_d是单个字符串(比如"CAN,MEX"),不是向量,%in%无法识别逗号分隔的内容,只会判断d是否等于整个rec_d字符串。- NA处理不符合预期:原代码中
is.na(rec_d)会让flag为1,但期望中C789的rec_d是NA时flag为0。
解决方案
方法1:使用stringr::str_detect
利用正则匹配判断d是否在逗号分隔的rec_d中,精准处理NA情况:
library(dplyr) library(stringr) result <- left_join(primary, secondary, by = c("id", "prod")) %>% mutate(flag = case_when( is.na(rec_d) ~ 0, str_detect(rec_d, fixed(d)) ~ 1, TRUE ~ 0 ))
fixed(d)确保匹配精确字符串,避免正则特殊字符干扰case_when清晰划分逻辑:NA时返回0,匹配到目标值返回1,其余情况返回0
方法2:拆分字符串后匹配(tidyr)
将rec_d拆分成多行匹配,再聚合结果:
library(dplyr) library(tidyr) result <- left_join(primary, secondary, by = c("id", "prod")) %>% separate_rows(rec_d, sep = ",") %>% mutate(flag = as.integer(d == rec_d)) %>% group_by(id, prod, d) %>% summarise(rec_d = paste(rec_d, collapse = ","), flag = max(flag, na.rm = TRUE)) %>% ungroup() %>% mutate(flag = ifelse(is.na(rec_d), 0, flag))
separate_rows把逗号分隔的字符串拆成每行一个独立值- 用
max(flag)判断是否存在匹配项,na.rm = TRUE忽略NA值干扰 - 最后单独处理
rec_d为NA的情况,将flag设为0
方法3:Base R 实现
不依赖tidyverse包的原生实现:
merged <- merge(primary, secondary, by = c("id", "prod"), all.x = TRUE) merged$flag <- mapply(function(d_val, rec_d_val) { if (is.na(rec_d_val)) return(0) d_val %in% strsplit(rec_d_val, ",")[[1]] }, merged$d, merged$rec_d) merged$flag <- as.integer(merged$flag)
mapply逐行处理每个d和rec_d组合strsplit拆分字符串为向量,再用%in%判断目标值是否存在
验证结果
运行上述任意方法后,可通过以下代码确认结果符合预期:
all.equal(result, desired) # [1] TRUE
内容的提问来源于stack exchange,提问作者vog
相关产品推荐
相关产品推荐

