You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 17:57:33