缘由

生信之路,道阻且长,记录经验,但渡有缘人。

碎碎念

及时当勉励,岁月不饶人 ——陶渊明

代码

在数据分析中,我们经常需要 “按组计算” ——
比如蛋白组学中:

对每个蛋白 (Protein),再按每个肽段 (Peptide) 分组,
计算每个实验组 (group) 的平均表达量。

这时我们可以选择三种方式:

1️⃣ split() —— base R 风格
2️⃣ nest() + map() —— tidyverse 风格
3️⃣ group_modify() —— tidyverse 极简风格


示例数据

library(tidyverse)
 
set.seed(123)
df <- tibble(
  Protein = rep(c("P1", "P2"), each = 6),
  Peptide = rep(c("pepA", "pepB"), each = 3, times = 2),
  group   = rep(c("WT", "KO", "AAV"), times = 4),
  value   = rnorm(12, 10, 1)
)
df

一、Base R 风格:split() + lapply()

protein_split <- split(df, df$Protein)
pep_split <- lapply(protein_split, function(x) split(x, x$Peptide))
 
result_base <- lapply(pep_split, function(protein_list) {
  lapply(protein_list, function(pep_df) {
    pep_df %>%
      group_by(group) %>%
      summarise(mean_val = mean(value))
  })
})

优点: 逻辑清晰、兼容性强
缺点: 嵌套层级多,合并结果麻烦,不易在管道中复用。


二、Tidyverse 风格:nest() + map()

df_nested <- df %>%
  group_by(Protein, Peptide, group) %>%
  nest()
 
 

现在,我们可以在 map() 中对每个小表计算:

df_nested %>%
  mutate(res = map(data, ~ summarise(.x, mean_val = mean(value)))) %>%
  select(-data) %>%
  unnest(res)

输出

ProteinPeptidegroupmean_val
P1pepAWT9.44
P1pepAKO10.82
P1pepAAAV9.69
…………

优点:

  • 数据结构更 tidy;
  • 用 unnest() 一步合并;
  • 可轻松扩展更复杂计算。

三、Tidyverse 极简风格:group_modify()

group_modify() 是 dplyr 的内置“分组 apply”工具,能自动完成拆分、计算和合并:

df_result <- df %>%
  group_by(Protein, Peptide, group) %>%
  group_modify(~ summarise(.x, mean_val = mean(value)))
 
df_result

优点:

  • 一步到位;
  • 自动合并;
  • 完全兼容管道风格;
  • 支持返回多行或多列结果。