Pandas 数据分组聚合 GroupBy 操作

FreeGuideOnline 最新 2026-07-08

Pandas 数据分组聚合 GroupBy 操作

1. 为什么需要分组聚合?

在数据分析中,我们经常需要将数据按照某种类别进行划分,然后计算各组的统计量(如总和、均值、计数等)。Pandas 的 groupby 操作正是为此设计,它遵循分裂-应用-合并(split-apply-combine)的策略:

  • 分裂:根据一个或多个键将数据拆分成多个组;
  • 应用:对每个组独立执行某种操作(聚合、变换、过滤);
  • 合并:将结果组合成一个新的数据结构。

它类似于 SQL 中的 GROUP BY,但功能更强大、语法更灵活。本教程将带你从零掌握 Pandas 的分组聚合操作。

2. 准备示例数据

我们使用经典的泰坦尼克号数据集,其中包含乘客的生存情况、船舱等级、性别、年龄等信息。

import pandas as pd

# 读取在线数据集
url = "https://raw.githubusercontent.com/datasciencedojo/datasets/master/titanic.csv"
df = pd.read_csv(url)

# 查看前5行
print(df.head())

主要列名及含义:

  • Survived:0 死亡,1 生还
  • Pclass:乘客等级(1 = 头等舱,2 = 二等舱,3 = 三等舱)
  • Sex:性别
  • Age:年龄
  • Fare:票价

3. GroupBy 对象的基本创建

使用 df.groupby('列名') 即可创建一个 GroupBy 对象。它本身不返回具体数据,只是一个分组映射。

# 按船舱等级分组
grouped = df.groupby('Pclass')
print(grouped)   # <pandas.core.groupby.generic.DataFrameGroupBy object at ...>

此时还没有进行任何计算,只有当你调用聚合函数时,才会真正执行运算。

4. 常用内置聚合函数

Pandas 提供了丰富的聚合方法,可以直接应用于 GroupBy 对象。

方法 说明
mean() 组均值
sum() 组总和
size() 组大小(包含 NaN)
count() 组中非空值的数量
std() 组标准差
min() / max() 组最小值 / 最大值
first() / last() 组内第一个 / 最后一个值

示例1:计算各等级船舱的平均票价

print(df.groupby('Pclass')['Fare'].mean())

输出:

Pclass
1    84.154687
2    20.662183
3    13.675550
Name: Fare, dtype: float64

示例2:统计各性别的生还人数(按生还列求和)

print(df.groupby('Sex')['Survived'].sum())

输出:

Sex
female    233
male      109
Name: Survived, dtype: int64

注意:

  • size() 返回的是包含缺失值的组大小,而 count() 只统计非空值。分组计数时优先使用 size()
  • 如果只选择一列进行聚合,返回的是 Series;若不指定列,聚合会应用到所有数值列,返回 DataFrame

5. 按多列分组

可以向 groupby() 传入一个列表,实现多个键的分组。

# 按等级和性别分组,计算平均年龄
multi_group = df.groupby(['Pclass', 'Sex'])['Age'].mean()
print(multi_group)

输出:

Pclass  Sex   
1       female    34.611765
        male      41.281386
2       female    28.722973
        male      30.740707
3       female    21.750000
        male      26.507589
Name: Age, dtype: float64

结果拥有多层索引(MultiIndex)。可以通过 .unstack() 将其展开为更易读的表格形式:

print(multi_group.unstack())

6. 使用 agg() 同时应用多个聚合

agg() 方法(别名 aggregate)可以在分组后对不同的列应用不同的聚合函数,或对同一列应用多个函数。

6.1 对单列应用多个聚合

# 对票价列计算均值和标准差
df.groupby('Pclass')['Fare'].agg(['mean', 'std'])

输出:

             mean        std
Pclass                      
1       84.154687  78.746457
2       20.662183  13.417399
3       13.675550  11.778142

6.2 对不同列指定不同的聚合

传入字典,键为列名,值为聚合函数(字符串或函数列表)。

df.groupby('Pclass').agg({
    'Age': 'median',          # 年龄中位数
    'Fare': ['min', 'max'],   # 票价最小值和最大值
    'Survived': 'mean'        # 生存率(均值)
})

此方法返回一个多层列索引的 DataFrame。

6.3 自定义聚合函数

可以将自定义的 Python 函数传递给 agg,例如计算极差(最大值-最小值)。

def range_func(x):
    return x.max() - x.min()

df.groupby('Pclass')['Age'].agg(range_func)

7. 高级 GroupBy 方法:transformfilterapply

除了聚合,GroupBy 还支持更灵活的逐组操作。

7.1 transform:组内广播

transform 会将函数的结果按照原索引广播,保持与原数据相同的形状。常用于缺失值填充、标准化等。

# 用各船舱等级的平均年龄填充年龄缺失值
df['Age'] = df.groupby('Pclass')['Age'].transform(lambda x: x.fillna(x.median()))

此处 transform 返回与传入对象同样长度的 Series,可直接用于赋值。

7.2 filter:根据组特征筛选整组数据

filter 根据每个组的布尔条件决定保留或丢弃整个组。

# 只保留组内成员数大于 200 的组(即只保留人数较多的等级)
filtered = df.groupby('Pclass').filter(lambda x: len(x) > 200)
print(filtered['Pclass'].unique())   # 所有等级都大于200?实际上三个组都大于200,可尝试其他阈值

更实际的用法:保留平均票价大于20的组。

# 这一步需要先计算组平均,然后筛选
avg_fare = df.groupby('Pclass')['Fare'].transform('mean')
filtered_df = df[avg_fare > 20]   # 但这是对所有行基于分组均值筛选,并非 filter

纯粹的 filter 示例:

# 仅保留组内 Fare 标准差小于 40 的等级
filtered = df.groupby('Pclass').filter(lambda x: x['Fare'].std() < 40)

7.3 apply:最通用的分组操作

apply 可以将任意函数应用到每个组,并灵活返回标量、Series 或 DataFrame。当内置方法无法满足时使用。

# 提取每组票价最高的前2名乘客信息
def top2_fare(group):
    return group.nlargest(2, 'Fare')

df.groupby('Pclass').apply(top2_fare)

注意:apply 可能会在结果中添加分组键作为索引,可以通过 .reset_index(drop=True) 清理。

8. 分组后迭代

GroupBy 对象支持迭代,返回元组 (组名, 子DataFrame)

for name, group in df.groupby('Pclass'):
    print(f"等级 {name} 的平均票价为 {group['Fare'].mean():.2f}")

9. 总结与最佳实践

  • 首选内置聚合:标准聚合(sum、mean、size 等)性能最高,可直接调用。
  • 使用 agg 执行复杂聚合:多函数、多列聚合时,agg 是最清晰的方式。
  • transform 用于保持形状:需填充组内均值或标准化特征时,避免手动循环。
  • filter 进行组级筛选:相比先聚合再合并索引,filter 更直接。
  • apply 作为万能武器:当其他方法无法实现时使用,但要注意性能,大数据集下可能较慢。

通过本教程,你已经掌握了 Pandas 分组聚合的核心技术。现在可以尝试用真实数据练习,例如分析销售数据中各地区的销售额总和、各产品类别的平均折扣等,逐步提升你的数据分析效率。