Pandas 是 Python 中强大的数据分析库,其 GroupBy 功能能够帮助用户对数据集进行分组并执行各种聚合操作。本文通过 NYC 职位数据集(包含职位 ID、职位名称、发布机构、职位类型以及薪资范围等信息)为例,详细讲解 GroupBy 的工作原理及应用方法,并在关键步骤中插入示例数据表以增强理解。
准备工作
在使用 GroupBy 功能之前,需要导入 Pandas 库并加载数据集。以下是导入 NYC 职位数据集的代码:
import pandas as pd
# 加载 NYC 职位数据集
data = pd.read_csv('nyc_jobs.csv')
示例数据表
以下是 NYC 职位数据集的一个简化示例,展示其主要列:
Job ID | Agency | Civil Service Title | Posting Type | Salary Range From | Salary Range To | Job Category |
510376 | Admin for Children's Svcs | Social Worker | External | 42731 | 50000 | Social Services |
510377 | Human Rights Commission | Analyst | Internal | 55000 | 65000 | Legal Affairs |
510378 | Admin for Children's Svcs | Case Worker | Internal | 45000 | 52000 | Social Services |
510379 | Board of Correction | Inspector | External | 60000 | 70000 | Public Safety |
GroupBy 的基本概念
GroupBy 功能允许用户根据指定列将数据集分割为多个子集,并对每个子集应用聚合函数(如均值、中位数等)。然而,初次使用 GroupBy 时,返回结果可能难以直接理解。例如:
# 按 Agency 列进行分组
grouped = data.groupby('Agency')
print(grouped)
运行上述代码,返回的是一个
pandas.core.groupby.generic.DataFrameGroupBy 对象,而非直观的数据表。这是因为 GroupBy 将数据集按 Agency 分割成多个子集,但未指定如何处理这些子集。
应用聚合函数
为了使分组结果更有意义,可以对分组应用聚合函数。例如,计算每个机构的 Salary Range From 列的均值:
# 计算每个机构的薪资范围均值
mean_salary = data.groupby('Agency')['Salary Range From'].mean()
print(mean_salary)
示例结果表
假设对上述示例数据执行此操作,结果可能如下:
Agency | Salary Range From (Mean) |
Admin for Children's Svcs | 43865.5 |
Board of Correction | 60000.0 |
Human Rights Commission | 55000.0 |
如果需要对所有数值列计算均值,可以省略列名,Pandas 会自动处理所有数值列:
# 对所有数值列计算均值
mean_all = data.groupby('Agency').mean()
print(mean_all)
示例结果表(多列均值)
Agency | Job ID (Mean) | Salary Range From (Mean) | Salary Range To (Mean) |
Admin for Children's Svcs | 510377.0 | 43865.5 | 51000.0 |
Board of Correction | 510379.0 | 60000.0 | 70000.0 |
Human Rights Commission | 510377.0 | 55000.0 | 65000.0 |
Pandas 支持多种聚合函数,包括均值(mean)、中位数(median)、最小值(min)、最大值(max)和求和(sum)等。更多操作可参考 Pandas GroupBy 文档。
应用多个聚合函数
可以同时对分组应用多个聚合函数。例如,计算每个机构的薪资范围均值和中位数:
# 应用多个聚合函数
result = data.groupby('Agency')['Salary Range From'].agg(['mean', 'median'])
print(result)
示例结果表
Agency | mean | median |
Admin for Children's Svcs | 43865.5 | 43865.5 |
Board of Correction | 60000.0 | 60000.0 |
Human Rights Commission | 55000.0 | 55000.0 |
自定义函数与分组
用户可以通过 apply 方法将自定义函数应用到分组。例如,定义一个计算均值的函数:
# 定义自定义函数
def custom_mean(group):
return group.mean()
# 应用自定义函数
result = data.groupby('Agency')['Salary Range From'].apply(custom_mean)
print(result)
要查看分组的结构,可以遍历每个分组:
# 查看每个分组的内容
for name, group in data.groupby('Agency'):
print(f"Group: {name}")
print(group['Salary Range From'])
print("***")
示例输出
Group: Admin for Children's Svcs
0 42731
2 45000
Name: Salary Range From, dtype: int64
***
Group: Board of Correction
3 60000
Name: Salary Range From, dtype: int64
***
Group: Human Rights Commission
1 55000
Name: Salary Range From, dtype: int64
***
多列分组
GroupBy 支持按多列分组。例如,按 Agency 和 Posting Type 分组:
# 按多列分组并计算均值
result = data.groupby(['Agency', 'Posting Type'])['Salary Range From'].mean()
print(result)
示例结果表
Agency | Posting Type | Salary Range From (Mean) |
Admin for Children's Svcs | External | 42731.0 |
Admin for Children's Svcs | Internal | 45000.0 |
Board of Correction | External | 60000.0 |
Human Rights Commission | Internal | 55000.0 |
若不希望分组列成为多级索引,可设置 as_index=False:
# 保留分组列作为普通列
result = data.groupby(['Agency', 'Posting Type'], as_index=False)['Salary Range From'].mean()
print(result)
示例结果表(普通列)
Agency | Posting Type | Salary Range From |
Admin for Children's Svcs | External | 42731.0 |
Admin for Children's Svcs | Internal | 45000.0 |
Board of Correction | External | 60000.0 |
Human Rights Commission | Internal | 55000.0 |
提取分组信息
GroupBy 对象提供多种方法提取分组信息。例如,获取每个分组的首行:
# 获取每个分组的首行
first_rows = data.groupby('Agency').first()
print(first_rows)
示例结果表
Agency | Job ID | Civil Service Title | Posting Type | Salary Range From | Salary Range To | Job Category |
Admin for Children's Svcs | 510376 | Social Worker | External | 42731 | 50000 | Social Services |
Board of Correction | 510379 | Inspector | External | 60000 | 70000 | Public Safety |
Human Rights Commission | 510377 | Analyst | Internal | 55000 | 65000 | Legal Affairs |
获取特定分组:
# 获取特定分组
human_rights_group = data.groupby('Agency').get_group('Human Rights Commission')
print(human_rights_group)
示例结果表
Job ID | Civil Service Title | Posting Type | Salary Range From | Salary Range To | Job Category |
510377 | Analyst | Internal | 55000 | 65000 | Legal Affairs |
使用 Grouper 处理时间序列
对于时间序列数据,pd.Grouper 提供灵活的分组方式。以下是一个模拟时间序列数据的示例:
# 创建模拟时间序列数据
time_data = pd.DataFrame({
'Publish Date': ['2000-01-02', '2000-01-02', '2000-01-09', '2000-01-16'],
'Price': [10, 20, 15, 25]
})
time_data['Publish Date'] = pd.to_datetime(time_data['Publish Date'])
# 按周分组并计算均值
weekly_groups = time_data.groupby(pd.Grouper(key='Publish Date', freq='1W'))['Price'].mean()
print(weekly_groups)
示例结果表
Publish Date | Price (Mean) |
2000-01-02 | 15.0 |
2000-01-09 | 15.0 |
2000-01-16 | 25.0 |
通过调整 freq 参数(如 2W 表示每两周),可以改变分组频率:
# 按两周分组
biweekly_groups = time_data.groupby(pd.Grouper(key='Publish Date', freq='2W'))['Price'].mean()
print(biweekly_groups)
示例结果表
Publish Date | Price (Mean) |
2000-01-02 | 15.0 |
2000-01-16 | 20.0 |
优化 GroupBy 性能
对于大型数据集,GroupBy 操作可能较慢。默认情况下,GroupBy 会对结果排序,增加计算时间。设置 sort=False 可提高性能:
# 禁用排序以提高性能
fast_group = data.groupby('Agency', sort=False)['Salary Range From'].mean()
print(fast_group)
总结
Pandas 的 GroupBy 功能是数据分析的强大工具,支持以下操作:
- 按单列或多列分组;
- 应用内置或自定义聚合函数;
- 处理时间序列数据;
- 优化大型数据集性能。