使用dplyr的summarise实现多层级均值聚合的简便方法
如何在dplyr中同时获取分组整体均值与子组均值?
你遇到的痛点我太懂了——重复写分组代码或者重构数据确实麻烦,其实用dplyr本身的功能就能轻松搞定,不用额外绕路。先回顾下你的示例数据:
dta <- read.table(header=TRUE, text=' subject sex condition measurement 1 M control 7.9 1 M cond1 12.3 1 M cond2 10.7 2 F control 6.3 2 F cond1 10.6 2 F cond2 11.1 3 F control 9.5 3 F cond1 13.1 3 F cond2 13.8 4 M control 11.5 4 M cond1 13.4 4 M cond2 12.9 ')
下面是三个简便的解决方案:
方法一:合并不同分组的结果(最直观)
先单独计算按sex的整体均值,给condition列标记为"total",再和按sex+condition分组的子组均值合并,最后排序让结果更清晰:
library(dplyr) combined_means <- dta %>% # 计算按sex的整体均值,标记condition为total group_by(sex) %>% summarise( condition = "total", mean = mean(measurement), .groups = "drop" ) %>% # 合并子组均值 bind_rows( dta %>% group_by(sex, condition) %>% summarise(mean = mean(measurement), .groups = "drop") ) %>% # 按sex和condition排序,方便查看 arrange(sex, condition) print(combined_means)
输出结果会同时包含每个sex的整体均值,以及每个sex下不同condition的分组均值:
# A tibble: 8 × 3 sex condition mean <chr> <chr> <dbl> 1 F cond1 11.9 2 F cond2 12.5 3 F control 7.9 4 F total 10.7 5 M cond1 12.9 6 M cond2 11.8 7 M control 9.7 8 M total 11.4
方法二:单次分组内同时计算两种均值(更紧凑)
利用dplyr的summarise配合across,在按sex分组的同时,一次性计算整体均值和各个condition的子组均值,最后转成长格式让结构统一:
library(dplyr) library(tidyr) # 仅用于转长格式,可选 combined_means <- dta %>% group_by(sex) %>% summarise( # 先计算整体均值 mean_total = mean(measurement), # 遍历每个condition,计算对应子组的均值 across(unique(condition), ~mean(measurement[condition == .x]), .names = "mean_{.x}") ) %>% # 转成长格式,和方法一的输出结构一致 pivot_longer( cols = starts_with("mean_"), names_to = "condition", values_to = "mean", names_prefix = "mean_" ) %>% arrange(sex, condition) print(combined_means)
这个方法的好处是只需要一次主分组,后续转长格式也只是为了统一结果结构,如果能接受宽格式的话,转长步骤可以省略。
方法三:用group_modify批量处理(适合复杂场景)
如果后续还要添加更多统计量(比如标准差、样本量),group_modify会更灵活——它允许你对每个sex分组单独处理,同时返回整体和子组的统计结果:
library(dplyr) combined_means <- dta %>% group_by(sex) %>% group_modify(~ { # 计算当前sex的整体均值 total_mean <- tibble(condition = "total", mean = mean(.x$measurement)) # 计算当前sex下各condition的子组均值 group_means <- .x %>% group_by(condition) %>% summarise(mean = mean(measurement), .groups = "drop") # 合并两个结果 bind_rows(total_mean, group_means) }) %>% ungroup() %>% arrange(sex, condition) print(combined_means)
这个方法扩展性很强,比如你想同时添加标准差,只需要在两个tibble里加上sd = sd(measurement)即可。
内容的提问来源于stack exchange,提问作者Eric Fail
相关产品推荐
相关产品推荐

