使用aggregate.data.frame聚合R的data.frame时维度不符问题排查
问题原因与解决办法
哈哈,你这是把aggregate的分组方向搞反啦!我来给你捋清楚问题出在哪,再给你几个靠谱的解决办法~
为什么你的aggregate代码出错?
你用的代码:
aggregate.data.frame(df, by=list(rep(1:3, each=3)), FUN='mean')
这里的by参数传入的rep(1:3, each=3)是一个长度为9的向量,刚好和你的df的行数(9行)一致。aggregate的默认逻辑是:根据by的分组变量对行进行分组,然后对每一列应用聚合函数。所以它会把第1-3行归为一组,4-6行一组,7-9行一组,然后计算每列在每组内的均值,最终得到3行9列的结果——完全和你想要的「每行内按A/B/C列组求均值」的需求反过来了!
正确的实现方法
方法1:Base R 原生实现(无需额外包)
我们可以先把列按前缀(A/B/C)分组,然后对每行计算每个组的均值:
# 提取列名的前缀(A/B/C)作为分组依据 col_groups <- substr(colnames(df), 1, 1) # 对每行数据,按列分组计算均值,再转置成需要的格式 result <- t(apply(df, 1, function(row) tapply(row, col_groups, mean))) # 转成data.frame并设置列名 result_df <- as.data.frame(result) colnames(result_df) <- unique(col_groups)
方法2:用dplyr+tidyr(tidyverse风格,更直观)
如果你熟悉tidyverse工具链,这种方法逻辑更清晰:
library(dplyr) library(tidyr) result_df <- df %>% # 给每行添加唯一ID,方便后续分组 mutate(row_id = row_number()) %>% # 把宽格式数据转成长格式 pivot_longer(-row_id, names_to = "col_name", values_to = "value") %>% # 从列名中提取A/B/C分组 mutate(group = substr(col_name, 1, 1)) %>% # 按行ID和分组计算均值 group_by(row_id, group) %>% summarise(mean_val = mean(value), .groups = "drop") %>% # 转回宽格式 pivot_wider(names_from = group, values_from = mean_val) %>% # 移除行ID列 select(-row_id)
方法3:用data.table(大数据量下更高效)
如果你的数据量很大,data.table的方法速度会更快:
library(data.table) # 把df转成data.table格式 setDT(df)[, row_id := .I] # 转长格式、分组计算均值、再转回宽格式 result_df <- melt(df, id.vars = "row_id")[, .(mean_val = mean(value)), by = .(row_id, group = substr(variable, 1, 1)) ][, dcast(.SD, row_id ~ group, value.var = "mean_val")][, row_id := NULL]
以上三种方法都能得到你想要的9行3列结果,每行对应原df的一行,列分别是A_、B_、C_*列的均值。
内容的提问来源于stack exchange,提问作者CiaranWelsh
相关产品推荐
相关产品推荐

