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

如何利用DataFrame列元素字符串批量筛选另一个DataFrame?

R批量筛选DataFrame匹配元素问题

输入数据

set.seed(1)
df1 <- data.frame(k1 = "AFD(1);Acf(2);Vgr7(2);"
                  ,k2 = "ABC(7);BHG(46);TFG(675);")

df2 <- data.frame(site =c("AFD(1);AFD(2);", "Acf(2);", "TFG(677);", 
"XX(275);",  "ABC(7);", "ABC(9);")
                  ,p1 = rnorm(6, mean = 5, sd = 2)
                  ,p2 = rnorm(6, mean = 6.5, sd = 2))

需求说明

df1的列由多组「字母/数字+括号内数字+分号」格式的元素组成长字符串;df2的site列包含部分来自df1的元素,元素可能单独成串或作为长串的一部分。

需要利用df1的所有列(列名不一定含k)和df2的site列批量筛选df2,最终结果首列为df1的列名,第二列为df2中包含对应df1列元素的site值,其余列保留df2的原有内容。预期结果如下:

> outcome
    k   site            p1          p2
1   k1  AFD(1);AFD(2);  4.043700    3.745881
2   k1  Acf(2);         5.835883    5.670011
3   k2  ABC(7);         5.775343    8.700051

遇到的问题

尝试两种方案均失败:

  • 方案1:单列生成grep模式但未转义括号,且无法批量处理
  • 方案2:拆分元素后丢失分隔符,无法处理部分匹配

解决方案

library(dplyr)
library(stringr)
library(tidyr)

# 处理df1,生成各列对应的匹配正则
df1_processed <- df1 %>%
  pivot_longer(everything(), names_to = "k", values_to = "raw_elements") %>%
  mutate(
    # 拆分元素并过滤空字符串
    elements = str_split(raw_elements, ";") %>% map(~ .x[.x != ""]),
    # 转义括号(正则中()为特殊字符,需转义才能匹配字面量)
    escaped_elements = map(elements, ~ str_replace_all(.x, fixed("("), "\\(") %>% str_replace_all(fixed(")"), "\\)")),
    # 合并为单个正则:匹配任意一个元素
    match_regex = map_chr(escaped_elements, ~ paste0("(", paste(.x, collapse = "|"), ")"))
  )

# 批量筛选并合并结果
outcome <- df1_processed %>%
  rowwise() %>%
  mutate(
    # 筛选df2中site包含当前列任意元素的行
    matched_data = list(filter(df2, str_detect(site, match_regex)))
  ) %>%
  unnest(matched_data) %>%
  select(k, site, p1, p2) %>%
  arrange(k)

# 输出结果
print(outcome)

代码说明

  1. 转置df1:用pivot_longer将df1转为长格式,方便逐列处理;
  2. 处理元素与正则:拆分每列的元素,转义括号避免正则解析错误,再将同列元素合并为「或逻辑」的正则表达式;
  3. 批量筛选合并:遍历每个df1的列,筛选df2中匹配的行,最后合并所有结果并整理列顺序。

内容的提问来源于stack exchange,提问作者Wera

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 23:01:54