在R中为指定条目多列查找多字符串并返回列名
问题描述
我需要在R语言中处理一个数据框,要求针对每个Item_Name条目,在Sample_A、Sample_B等多列里查找包含"0/1"或"1/1"的字符串,并返回对应的列名。目前我只会用grepl单次查找一个模式,也不清楚如何获取符合条件的列名,现有代码如下:
data_frame_mod <- dataframe[Reduce(`|`, lapply(dataframe, grepl, pattern = "0/1"))]
解决方法
你的现有代码是用来筛选出至少有一列包含"0/1"的行,而非提取每行对应的符合条件的列名。以下是两种实用的实现方案:
方法1:基础R的apply函数
先构造示例数据框用于演示:
# 示例数据框 dataframe <- data.frame( Item_Name = c("Item1", "Item2", "Item3"), Sample_A = c("0/0", "0/1", "1/1"), Sample_B = c("1/1", "0/0", "0/1"), Sample_C = c("0/0", "1/1", "0/0"), stringsAsFactors = FALSE )
通过apply逐行处理,提取符合条件的列名:
# 定义匹配规则:同时匹配"0/1"或"1/1" pattern <- "(0/1|1/1)" # 逐行提取匹配列名并整理为数据框 result <- data.frame( Item_Name = dataframe$Item_Name, Matching_Samples = apply(dataframe[, -1], 1, function(row) { # 获取当前行中符合匹配规则的列名,用逗号分隔 paste(names(row)[grepl(pattern, row)], collapse = ", ") }) ) print(result)
输出结果:
Item_Name Matching_Samples 1 Item1 Sample_B 2 Item2 Sample_A, Sample_C 3 Item3 Sample_A, Sample_B
方法2:tidyverse风格(dplyr+tidyr)
如果习惯使用tidyverse工具链,这种写法更直观,还能处理无匹配的情况:
library(dplyr) library(tidyr) result <- dataframe %>% # 将宽数据转为长数据,方便筛选 pivot_longer(cols = starts_with("Sample_"), names_to = "Sample", values_to = "Genotype") %>% # 筛选出符合匹配规则的行 filter(grepl(pattern, Genotype)) %>% # 按Item_Name分组,合并对应的列名 group_by(Item_Name) %>% summarise(Matching_Samples = paste(Sample, collapse = ", ")) %>% # 补全所有Item_Name条目,无匹配的标记为"无匹配" right_join(dataframe %>% select(Item_Name), by = "Item_Name") %>% replace_na(list(Matching_Samples = "无匹配")) print(result)
关键说明
- 正则表达式
"(0/1|1/1)"实现了同时匹配两种目标字符串,grepl默认支持正则语法,|表示“或”的逻辑关系。 - 获取列名的核心逻辑是:先定位每行中符合条件的列位置,再用
names()提取对应列名,最后合并为字符串格式。
内容的提问来源于stack exchange,提问作者user5029313
相关产品推荐
相关产品推荐

