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

在R中跨列查找特定字符组合并匹配对应sampleID

R:匹配字符组合对应的样本ID

需求说明

现有两个R数据框:

  • df1:存储特定字符组合(实际数据每行的组合元素数量不固定)
  • df2:包含样本ID列表及各样本的字符拥有情况

需要为df1的每一行字符组合,找出df2中包含该组合所有字符的样本ID(样本可拥有额外字符,同一样本ID可出现在df1的多行结果中)。

示例数据

df1 <- data.frame(entry1 = c("A","B","C"),
                  entry2 = c("D","E","F"),
                  entry3 = c("G","H","I"))

df2 <- data.frame(sampleID = c("1001","1002","1003","1004","1005"),
                  "A" = c("A","0","0","A","A"),
                  "B" = c("B","B","B","0","0"),
                  "C" = c("0","0","0","C","C"),
                  "D" = c("D","0","D","0","0"),
                  "E" = c("E","E","0","0","0"),
                  "F" = c("0","0","0","F","F"),
                  "G" = c("G","0","0","G","0"),
                  "H" = c("H","H","H","H","0"),
                  "I" = c("0","0","I","O","0"))

期望输出

df1.2 <- data.frame(entry1 = c("A","B","C"),
                    entry2 = c("D","E","F"),
                    entry3 = c("G","H","I"),
                    sampleID.1 = c("1001","1001",""),
                    sampleID.2 = c("","1002",""))

解决方案

用dplyr和tidyr包实现高效匹配,避免低效循环,同时兼容df1每行元素数量不固定的场景:

步骤1:预处理df2,生成每个样本的字符集合

先把df2转换为长格式,过滤掉无字符的"0",再为每个样本整理出拥有的字符列表:

library(dplyr)
library(tidyr)

df2_processed <- df2 %>%
  pivot_longer(-sampleID, names_to = "char", values_to = "value") %>%
  filter(value != "0") %>%
  group_by(sampleID) %>%
  summarise(chars = list(char)) %>%
  ungroup()

步骤2:预处理df1,生成每行的需求字符集合

提取df1每行的非空字符(适配元素数量不固定的场景):

df1_processed <- df1 %>%
  rowwise() %>%
  mutate(
    required_chars = list(c_across(everything()) %>% na.omit())
  ) %>%
  ungroup()

步骤3:匹配符合条件的样本ID

对df1的每一行,筛选出df2中字符集合包含所有需求字符的样本:

df1_with_samples <- df1_processed %>%
  rowwise() %>%
  mutate(
    matched_samples = list(df2_processed$sampleID[
      sapply(df2_processed$chars, function(x) all(required_chars %in% x))
    ])
  ) %>%
  ungroup() %>%
  select(-required_chars)

步骤4:转换为期望的宽格式

将匹配到的样本ID拆分为单独列,空值填充为空白字符串:

# 确定最多需要多少个样本列
max_sample_cols <- max(sapply(df1_with_samples$matched_samples, length))

# 拆分并重命名列
df1.2 <- df1_with_samples %>%
  unnest_wider(matched_samples, names_sep = ".") %>%
  mutate(across(starts_with("matched_samples."), ~ ifelse(is.na(.), "", .))) %>%
  rename_with(~ gsub("matched_samples.", "sampleID.", .), starts_with("matched_samples."))

# 填充不足的列(如果有的话)
for(col_idx in (ncol(df1)+1):(ncol(df1)+max_sample_cols)) {
  col_name <- paste0("sampleID.", col_idx - ncol(df1))
  if(!col_name %in% colnames(df1.2)) {
    df1.2[[col_name]] <- ""
  }
}

# 查看结果
df1.2

运行后即可得到与期望输出一致的结果,同时该方法能高效处理更大规模的数据,也兼容df1每行元素数量不固定的情况。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 01:42:57