R语言数据框按rank_code的S标记分组求和perc_fragments的实现方法
核心实现逻辑
不需要做复杂的字符串正则匹配,按行顺序累计标记组边界即可:每当rank_code严格等于"S"时,为后续所有行开启新分组,直到遇到下一个"S"才切换分组。
- 关键技巧:用
cumsum(rank_code == "S")直接生成每组唯一ID,无需循环、无需匹配物种名称,完美规避之前用grepl匹配不准的问题。 - 预处理注意:原始数据中
perc_fragments为字符串类型,必须转为数值型才能完成求和计算。
可直接运行的代码
Tidyverse 版本(简洁易维护)
library(dplyr) # 你的原始测试数据 df <- structure(list(ref = c("Sample1", "Sample1", "Sample1", "Sample1", "Sample1", "Sample1", "Sample1", "Sample1", "Sample1", "Sample1", "Sample1", "Sample1", "Sample1", "Sample1", "Sample1", "Sample1", "Sample1", "Sample1", "Sample1", "Sample1", "Sample1"), perc_fragments = c("73.43", "2.10", "1.40", "0.70", "1.40", "0.70", "0.70", "0.70", "0.70", "0.70", "0.70", "0.70", "0.70", "0.70", "0.70", "1.40", "0.70", "0.70", "0.70", "1.40", "1.40"), rank_code = c("S", "S1", "S1", "S2", "S1", "S1", "S1", "S1", "S1", "S2", "S1", "S1", "S1", "S1", "S1", "S", "S", "S", "S", "S", "S1"), scientific_name = c("Escherichia coli", "Escherichia coli P12b", "Escherichia coli O157:H7", "Escherichia coli O157:H7 str. SS17", "Escherichia coli CFT073", "Escherichia coli O6:H16", "Escherichia coli APEC IMT5155", "Escherichia coli UM146", "Escherichia coli C", "Escherichia coli ATCC 8739", "Escherichia coli FAP1", "Escherichia coli O27:H7", "Escherichia coli IAI1", "Escherichia coli O127:H6", "Escherichia coli PCN061", "Klebsiella pneumoniae", "Klebsiella variicola", "Citrobacter freundii", "Shigella dysenteriae", "Staphylococcus aureus", "Staphylococci haemolyticus" )), row.names = c(NA, -21L), class = c("tbl_df", "tbl", "data.frame" )) # 处理流程 result <- df |> mutate(perc_fragments = as.numeric(perc_fragments)) |> # 生成分组ID:遇到新的S即累计计数+1 mutate(group_id = cumsum(rank_code == "S")) |> group_by(group_id) |> summarise( ref = first(ref), rank_code = "S", scientific_name = first(scientific_name), perc_fragments = sum(perc_fragments) ) |> select(-group_id)
基础R版本(无需额外安装包)
# 预处理 df$perc_fragments <- as.numeric(df$perc_fragments) df$group_id <- cumsum(df$rank_code == "S") # 聚合求和 perc_sum <- aggregate(perc_fragments ~ ref + group_id, df, sum) # 提取每个分组对应的S行物种名 sci_name <- aggregate(scientific_name ~ group_id, df, \(x) x[1]) # 合并结果 result <- merge(perc_sum, sci_name, by = "group_id") result$rank_code <- "S" # 调整列顺序 result <- result[, c("ref", "perc_fragments", "rank_code", "scientific_name")]
多样本适配提示
如果数据包含多个不同的ref样本(如Sample1、Sample2等),需要在生成group_id时按ref先分组,避免跨样本串组:
# Tidyverse中调整后的分组ID生成逻辑 df |> group_by(ref) |> mutate(group_id = cumsum(rank_code == "S")) |> ungroup()
实现效果验证
以上代码运行后输出的结果完全匹配提出的分组规则:
- 第一组覆盖首个S行及其后续所有S1/S2行,求和后保留对应S行的物种名
- 独立的S行各自单独成组,保留自身对应的物种名
- S行之后紧跟的S1/S2行全部归到前序最近的S所在分组,最终保留S行的物种名作为组名称
内容的提问来源于stack exchange,提问作者Haakonkas
相关产品推荐
相关产品推荐

