R 中的数据聚合
了解在 R 中对数据进行聚合和分组的方法。
聚合方法
**聚合** 是数据分析中的关键步骤,因为它能够将大规模数据集汇总并压缩为更易于管理且具有意义的信息片段。通过数据聚合,我们可以识别出在原始数据中可能不明显的趋势、模式和关系。
例如,我们可以使用聚合来计算不同产品的平均销售额或总购买次数。这些聚合结果可以为商业决策提供依据,比如确定哪些产品应重点开发,或针对哪些客户群体开展促销活动。
聚合最常见的用途是计算数据的统计指标,如均值、总和、标准差、方差、范围或中位数。
summarize() 函数
summarize() 函数用于计算传入变量的聚合值。它结构灵活,允许按顺序添加额外列到输出结果中,并支持为包含聚合结果的列命名。
该函数至少需要两个输入参数:数据集和用聚合计算包裹的列名。输出结果即为语法中指定的聚合值。我们可以使用常见的统计函数作为计算方法,如 mean()、median()、sd() 和 sum()。
1# 标准结构 2summarize(<数据>, <方法>(<列>)) 3summarize(customers, sum(purchases)) # 示例 4 5# ----- 或者 ----- 6# 管道结构 7<data> %>% summarize(<方法>(<列>)) 8customers %>% summarize(sum(purchase)) # 示例
以下示例将在 iris 数据集上展示 summarize() 的功能。我们将计算均值、中位数和标准差,并结合 filter() 在管道中使用。
请查看以下示例:
1## 本练习中使用 CO2 和 iris 数据集 2library(dplyr) 3# 计算 Sepal.Length 列的均值 4print('----- 计算 iris 数据集的 Sepal.Length 列:---') 5agg1 <- summarise(iris, mean(Sepal.Length)) 6print(agg1) # 输出计算结果 7print('----- Sepal.Length 列的均值、中位数和标准差:--') 8# 计算多个聚合值,并手动命名列 9agg2 <- summarise(iris, avg = mean(Sepal.Length), stnd_dv = sd(Sepal.Length), med = median(Sepal.Length)) 10print(agg2) # 输出计算结果 11print('-------- 先过滤数据再计算聚合值:----') 12# 先过滤 conc 值小于 250 或大于 500 的行,然后使用管道计算行数、总和与均值 13agg3 <- CO2 %>% filter(conc < 250 | conc > 500) %>% summarise(number = n(), total = sum(conc), avg = mean(conc)) 14print(agg3) # 输出计算结果 15print('-------- 过滤和聚合后数据的预览:---') 16# 过滤数据后,新增一列显示累计值除以总和 17# 该计算表示当前行之前已覆盖的总数据比例 18agg4 <- CO2 %>% filter(conc < 250 | conc > 500) %>% summarise(percentage = cumsum(conc) / sum(conc)) 19print(head(agg4)) # 输出前 5 行计算结果 20print('-------- 过滤和聚合后数据的最后几行:---') 21print(tail(agg4)) # 输出最后 5 行计算结果
-
第 5 行:我们计算了
Sepal.Length列的均值。 -
第 9 行:我们计算了
Sepal.Length列的均值、标准差和中位数,并将这些结果分别命名为avg、stnd_dv和med。 -
第 13 行:我们先筛选出
conc值小于 250 或大于 500 的行,然后计算这些行的行数、总和和均值。 -
第 19 行:我们同样先进行筛选,随后计算累计和与总和的比值,以观察数据累积占比。
以下是数据分析师常用的其他聚合函数:
- `cummax()`:累计最大值,返回当前行之前所有行的最大值
- `cumsum()`:累计和,返回当前行之前所有行的总和。`cummin()` 和 `cummean()` 也类似
某些聚合函数在数据包含空值时会返回 NULL,因为无法处理缺失值。
我们可以通过在聚合函数中使用 na.rm= 参数来解决此问题。当设置为 TRUE 时,该参数可使计算忽略空值。
请看以下示例:
1# 本练习中使用 airquality 数据集 2library(dplyr) 3print(head(airquality)) 4print('---- 不使用 na.rm 参数的聚合结果:----') 5agg1 <- airquality %>% summarise(avg_oz = mean(Ozone), sd_oz = sd(Ozone)) 6print(agg1) 7print('---- 使用 na.rm 参数的聚合结果:----') 8agg2 <- airquality %>% summarise(avg_oz = mean(Ozone, na.rm = TRUE), sd_oz = sd(Ozone, na.rm = TRUE)) 9print(agg2)
注意输出之间的差异。第 5 行和第 8 行代码几乎相同,唯一的区别在于后者包含了 na.rm= 参数。
按组聚合数据
按类别对数据进行分组是数据分析中揭示模式的强大技术。我们可以深入探索特定数据子集的特征。例如,企业可以计算居住在德克萨斯州和纽约州人员的平均薪资,并据此对这两类人群做出推断。这些特征有助于企业为每个群体制定定制化策略。
在 R 中,我们可以充分利用这一技术。group_by() 和 summarize() 函数组合在需要深入分析细节时非常实用。
group_by() 函数接收列名作为输入,为每个唯一值生成分组,这些分组可用于后续的聚合计算。
1<data> %>% group_by(<列>) # 语法结构
以下是一些示例:
1library(dplyr) # 本练习所需的关键库 2print('------------ 数据集预览:------------') 3head(CO2) 4print('---- 按 Treatment 列不同类别计算聚合值:----') 5grouped1 <- CO2 %>% group_by(Treatment) %>% # 按 'Treatment' 列分组 6 summarise(avg = mean(uptake, na.rm = TRUE), number = n()) # 计算每组的均值和行数 7print(grouped1) 8print('---- 按 Plant 和 Treatment 两列分组后进行聚合计算:----') 9# 按两个不同列分组 10grouped2 <- CO2 %>% filter(uptake < 30) %>% # 筛选 uptake 值小于 30 的行 11 group_by(Plant, Treatment) %>% # 对筛选后的数据按两个列分组 12 summarize(avg = mean(uptake), number = n(), .groups = 'drop') # 计算每组的均值和行数 13print(grouped2)
-
第 5 行:我们计算了
Treatment列中各分类组的聚合值。 -
第 10 行:我们筛选出
uptake值小于 30 的行。 -
第 11 行:我们将数据按
Plant和Treatment两列的组合进行分组。 -
第 12 行:我们计算了每对
Plant和Treatment分组下的uptake均值和行数。由于Plant列在参数中优先级更高,因此它在分组中具有优先地位。
注意:当数据按多列分组时,
summarize()函数需使用.groups = 'drop'参数才能正常运行。否则,数据仅按第一列分组。
aggregate() 函数
aggregate() 函数的工作方式与 group_by 和 summarize 的组合非常相似。
它接受四个参数:
- 目标列:函数在此列上执行计算。
- 参考列:数据根据参考列中的类别进行分组。我们使用
~符号表示目标列与参考列之间的关系。 - 数据:指明数据集变量的名称。
- 测量方法:指明聚合类型,如均值、中位数或行数。
1## 聚合数据的通用示例 2aggregate(sales ~ customers, data, mean)
另一种使用方式是提供:
- 数据
- 通过
by参数指定参考列 - 通过
FUN参数指定计算方法
1## 聚合数据的通用示例 2aggregate(data[, c('sales', 'revenue')], by = list(data$customer), FUN = mean)
示例中仅展示了两种聚合方法,你可以自由更换方法以加深理解。
以下是具体示例:
1# 本练习中使用 'iris' 数据集 2library(dplyr) 3print('------- iris 数据集预览:----------') 4print(head(iris)) 5print('------- Species 列中的类别名称:----------') 6print(unique(iris$Species)) 7print('------ 按 Species 列各分类组计算 Sepal.Width 的均值:--') 8# 按 Species 列中的类别对 Sepal.Width 列的数据进行聚合 9# 函数接收目标列 (Sepal.Width) 与参考列 (Species) 的组合 10# 以及数据集 (iris) 和计算方法 (mean) 11agg1 <- aggregate(Sepal.Width ~ Species, iris, mean) 12print(agg1) # 输出结果 13print('------ 按 Species 列类别对前四列进行聚合:-') 14# 对 iris 数据集中第 1 至第 4 列按 Species 列的类别进行聚合 15# 计算前四列的均值 16agg2 <- aggregate(iris[, 1:4], by = list(reference = iris$Species), FUN = sd) 17print(agg2)
-
第 6 行:我们获取了
Species列中的类别名称。 -
第 11 行:我们按
Species列中的每个类别对Sepal.Width的值进行聚合。 -
第 16 行:我们按
Species列中的每个类别对第 1 至第 4 列的值进行聚合。
如上所示,aggregate() 函数支持多种结构。选择最适合你风格的方式即可。