如何在R中按特定分组条件计算指定列的平均值?
R语言分组计算均值的代码优化方案
我有一个包含500多行、11列的数据框df,样本数据如下:
Subject Group RA TA Trial VA1 VA2 VA3 VB1 VB2 VB3 1 CAI 0 1 1 6.289 5.924 7.194 4.058 9.770 -3.479 1 CAI 0 1 2 10.512 6.376 8.058 1.905 8.031 -10.698 1 CAI 0 1 3 6.554 5.046 9.482 1.825 7.152 -9.608 1 CAI 0 2 1 8.235 3.006 8.054 2.816 9.911 -4.125 1 CAI 0 2 2 6.744 2.176 9.751 3.566 12.217 -8.225 2 CAI 45 1 1 5.321 5.781 7.821 4.402 6.420 4.125 2 CAI 45 2 1 7.594 4.472 8.053 5.226 5.417 2.481 2 CAI 45 3 1 5.918 5.771 10.154 4.602 5.727 2.092 2 CAI 45 3 2 6.884 5.292 9.180 4.323 4.449 2.191
需要按Subject、Group、RA、TA组合分组,对每组内的VA1至VB3列计算所有Trial的平均值,期望输出格式如下:
Subject Group RA TA VA1 VA2 VA3 VB1 VB2 VB3 1 CAI 0 1 7.785 5.782 8.244 2.596 8.317 -7.928 1 CAI 0 2 7.490 2.591 8.902 3.191 11.064 -6.175 2 CAI 45 1 5.321 5.781 7.821 4.402 6.420 4.125 2 CAI 45 2 7.594 4.472 8.053 5.226 5.417 2.481 2 CAI 45 3 6.401 5.532 9.667 4.463 5.088 2.142
原循环代码可运行,但缺失Group列,且效率较低,原代码如下:
attach(df) factor(Subject) factor(Group) factor(RA) factor(TA) ndf = c() SubjList <- list(1,2) RAList <- list(0, 45, -45) TAList <- list(1,2,3,4) for (S in SubjList){ for (R in RAList){ for (T in TAList){ TEMP <- subset(M, (Subject == S & RA == R & TA ==T )) mVA1 = mean(TEMP$VA1) mVA2 = mean(TEMP$VA2) mVA3 = mean(TEMP$VA3) mVB1 = mean(TEMP$VB1) mVB2 = mean(TEMP$VB2) mVB3 = mean(TEMP$VB3) lst = c(S, R, T, mVA1, mVA2, mVA3, mVB1, mVB2, mVB3) ndf <- rbind(ndf, lst) } } }
原代码问题分析
- 手动嵌套循环效率低下,500行数据会增加不必要的运行时间
- 硬编码分组列表(
SubjList、RAList等),数据新增类别时会出错 - 未提取
Group列信息,导致输出缺失该关键列 - 使用
attach()容易引发变量命名冲突,属于不推荐的写法 - 循环中反复用
rbind()拼接数据框,每次都会复制整个数据,性能损耗大
优化方案一:Base R 实现
利用aggregate()函数直接分组计算,无需手动循环:
# 定义需要计算均值的列 value_cols <- c("VA1", "VA2", "VA3", "VB1", "VB2", "VB3") # 按指定列分组,计算均值 result_df <- aggregate(df[value_cols], by = list(Subject = df$Subject, Group = df$Group, RA = df$RA, TA = df$TA), FUN = mean, na.rm = TRUE) # 可选:处理缺失值 # 查看结果 print(result_df)
优化方案二:Tidyverse 实现(更简洁易读)
使用dplyr包的分组聚合语法,代码更直观:
library(dplyr) result_df <- df %>% group_by(Subject, Group, RA, TA) %>% summarise(across(c(VA1:VB3), mean, na.rm = TRUE), .groups = "drop") # 查看结果 print(result_df)
方案说明
- 两种方案都会自动保留
Group列,无需手动处理 - 无需硬编码分组的类别列表,自动识别数据中的所有组合
- 避免了
attach()的风险,代码更安全 - 性能远优于手动循环,尤其是数据量较大时
na.rm = TRUE参数可以处理数据中的缺失值,如果数据无缺失可省略
内容的提问来源于stack exchange,提问作者Anthony Laigo
相关产品推荐
相关产品推荐

