按组统计行数:table()
最简单的分组问题是“每种各有多少?”,base R 一次调用就能回答。table() 统计每个值出现的次数:
传入一列得到每个值的计数;传入两列得到完整的交叉表(地区作为行,套餐作为列)。想知道“占比多少?”,就用 prop.table(table(...)) 包起来。table() 是在 R 中得到频数的最快方式,如果你只需要一个计数,就别动用更重的工具。
每组一个统计量:tapply()
tapply(values, groups, function) 按第二个向量拆分第一个向量,并对每一块应用函数:
结果是一个具名向量:组标签作为名称,统计量作为值,非常适合快速查找(means["EU"])。这个名字可以理解为 “table apply”:沿着分组表应用一个函数。它和 sapply()、lapply() 属于同一个系列,详见 apply 函数族文档。
tapply() 的局限在于形状:具名向量不方便合并、绘图或继续处理。当汇总结果只是中间步骤而不是最终答案时,你需要得到一个数据框,而这正是下一个工具返回的东西。
公式主力:aggregate()
aggregate() 是 base R 中功能完整的分组工具:它返回一个数据框,它的公式接口读起来就像你会说的那句话。value ~ group 的意思是“value,按 group 拆分”:
增加分组变量只需在公式中加上 + another_column:第二次调用按 region 和 quarter 的每种组合求和。你还可以用 cbind(a, b) ~ group 一次汇总多个值列。因为输出是一个普通的数据框,所以可以直接用于合并、排序或绘图:做分组汇总时,这是 base R 中默认首选的工具。
有一个不声不响的行为要了解:公式接口在汇总之前,会丢掉所用的任意一列中含有 NA 的行。这通常正是你想要的;偶尔它也能解释为什么某个计数看起来偏低。
dplyr 的写法:group_by() + summarize()
现代的标准写法是 dplyr 的两个动词组合:group_by() 声明分组,summarize() 把每组折叠成一行,你列出多少个统计量就计算多少个(下面是静态代码,在线环境只能运行 base R):
library(dplyr)
sales |>
group_by(region) |>
summarize(
n = n(),
total = sum(amount),
avg = mean(amount)
)
这正是 dplyr 真正胜过 base R 的地方:一次可读的调用就能求出每组的多个统计量(aggregate() 要做到这一点得费一番周折),还附送 n(),结果可以直接流入下一个管道。(summarise() 是同一个函数,只是英式拼写。)
有一点常让新手困惑:有多个分组变量时,summarize() 只会去掉最后一个,结果仍然是分组状态,并且会打印一条相关提示。用 .groups 参数明确说明你想要什么:summarize(avg = mean(amount), .groups = "drop") 返回一个普通的、未分组的数据框,这是正确的默认习惯。一个分组状态的数据框如果混进后面的代码,会让 mutate() 等函数悄悄按组运算,这是令人困惑的结果的经典来源。
如何选择
- 计数:用
table(),一次调用就够了,没有更好的。 - 一个统计量,快速查看:用
tapply(),直接从具名向量中读出答案。 - 需要输出数据框,且只能用 base R:用带公式的
aggregate()。 - 多个统计量、流水线的一部分,或者任何更复杂的需求:用
group_by() |> summarize()。
它们之中没有错误的选择,算出的数字都一样,但根据你需要的输出形状来选工具,能省掉事后的转换步骤。平均值、中位数和离散程度本身的讲解,请看描述性统计。
完整示例:按气缸数汇总 mtcars
在一个内置数据集上把所有内容串起来:按气缸数统计汽车数量,以及它们的平均油耗和马力:
11 辆 4 缸汽车,平均约 26.7 mpg;7 辆 6 缸汽车,约 19.7;14 辆 8 缸汽车,约 15.1,而马力则朝相反方向递增。两次调用,一整张汇总表:分组汇总存在的意义,就是回答这类问题。
要点总结
- 用
table()计数,用prop.table()求占比。 tapply(values, groups, fn)返回具名向量,适合快速查看和查找。aggregate(value ~ group, data, FUN)返回数据框;用+增加分组变量,用cbind()增加值列。- dplyr 的
group_by() |> summarize(n = n(), avg = mean(x), .groups = "drop")是计算多个统计量的现代标准写法。 - 根据输出形状来选择;它们算出的数字都一样。
下一篇:合并共享同一个键的表格,包括 merge() 和 dplyr 的 join 系列函数。
常见问题
在 R 中怎么按组计算平均值?
base R 有两个工具:tapply(df$value, df$group, mean) 返回一个由各组平均值组成的具名向量,aggregate(value ~ group, data = df, FUN = mean) 以数据框的形式返回同样的结果。用 dplyr 则是:df |> group_by(group) |> summarize(avg = mean(value))。
在 R 中怎么按组统计出现次数?
table(df$group) 一次调用就能统计每个组值的行数;table(df$a, df$b) 对两列做交叉表。在 dplyr 中,count(df, group) 做同样的事,并返回一个数据框,更方便继续处理。
R 中 aggregate() 有什么作用?
aggregate() 按一个或多个分组列拆分数据框,对每一块应用一个函数,然后以数据框的形式返回结果。它的公式接口读起来很自然:aggregate(sales ~ region + quarter, data = df, FUN = mean) 的意思是:sales 按 region 和 quarter 分组,求平均值。
tapply 和 aggregate 有什么区别?
计算相同,输出形状不同。tapply() 返回一个具名向量(两个分组变量时返回数组),适合快速查找。aggregate() 返回一个数据框,当结果还要用于后续分析、合并或绘图时更好用。拿不准时,就用 aggregate()。