Pandas groupby怎么用?从入门到实战的分组聚合完全指南

 更新时间:2026年08月05日 09:21:14   作者:菜冻鱼  
还在为Pandas的groupby操作头疼吗?本文带你从零掌握分组聚合、transform变换、filter筛选与apply高级操作,结合agg多函数聚合和自定义函数,轻松应对数据分析中的分组需求,让你的数据处理效率翻倍

df.groupby() 是 Pandas 最强大的功能之一,遵循分 裂-应用-组合(Split-Apply-Combine)范式。

GroupBy 基础

创建 GroupBy 对象

import pandas as pd
import numpy as np

df = pd.DataFrame({
    '部门': ['销售', '销售', '技术', '技术', '人事', '人事'],
    '员工': ['张三', '李四', '王五', '赵六', '钱七', '孙八'],
    '工资': [8000, 9000, 15000, 12000, 7000, 7500],
    '奖金': [2000, 2500, 3000, 3500, 1500, 1800],
    '入职年份': [2019, 2021, 2018, 2020, 2022, 2021]
})

# 按单列分组
grouped = df.groupby('部门')
# 返回 DataFrameGroupBy 对象,尚未执行任何计算

# 按多列分组
multi_grouped = df.groupby(['部门', '入职年份'])

# 查看分组
print(grouped.groups)        # 返回 {组名: 行索引列表}
print(grouped.indices)       # 同上但返回 numpy 数组
print(grouped.ngroups)       # 分组数量
for name, group in grouped:
    print(name, group.shape) # 遍历每个组

聚合(Aggregation)

1. 基本聚合函数

# 对单个列聚合
print(grouped['工资'].sum())       # 每组工资总和
print(grouped['工资'].mean())      # 每组工资均值
print(grouped['工资'].count())     # 每组非空计数
print(grouped['工资'].std())       # 标准差
print(grouped['工资'].min())       # 最小值
print(grouped['工资'].max())       # 最大值
print(grouped['工资'].median())    # 中位数
print(grouped['工资'].first())     # 第一个值
print(grouped['工资'].last())      # 最后一个值
print(grouped['工资'].nunique())   # 唯一值数
print(grouped['工资'].var())       # 方差
print(grouped['工资'].sem())       # 均值的标准误差
print(grouped['工资'].quantile(0.75))  # 0.75 分位数

2.agg()— 多函数聚合 

# 方式一: 传入函数列表
result = grouped['工资'].agg(['sum', 'mean', 'std', 'count'])
print(result)
#           sum    mean     std  count
# 部门
# 人事   14500    7250    353.5      2
# 技术   27000   13500   2121.3      2
# 销售   17000    8500    707.1      2

# 方式二: 传入字典 -> 对不同列应用不同聚合
result = grouped.agg({
    '工资': ['sum', 'mean'],
    '奖金': ['min', 'max', 'sum']
})
print(result)

# 方式三: 命名聚合(推荐!)
result = grouped.agg(
    总工资=('工资', 'sum'),
    平均工资=('工资', 'mean'),
    最高奖金=('奖金', 'max'),
    人数=('员工', 'count')
)
print(result)

3. 常用内置字符串聚合

函数名说明函数名说明
'sum'求和'prod'乘积
'mean'均值'std'标准差
'median'中位数'var'方差
'min'最小值'max'最大值
'count'非空计数'size'包括 NaN 的计数
'first'第一个'last'最后一个
'nunique'唯一值数'sem'均值标准误
'quantile'分位数'ohlc'Open-High-Low-Close

4. 自定义聚合函数

# 自定义函数
def range_func(x):
    return x.max() - x.min()

print(grouped['工资'].agg(range_func))
print(grouped['工资'].agg(lambda x: x.max() - x.min()))

# 多列自定义
print(grouped.agg(lambda x: x.max() - x.min()))

Transform — 组内变换

transform 返回与原始 DataFrame 等长的 Series,非常适合做组内标准化。

# 组内减去均值(去中心化)
df['工资_组内去中心'] = grouped['工资'].transform(lambda x: x - x.mean())

# 组内 Z-Score 标准化
df['工资_ZScore'] = grouped['工资'].transform(
    lambda x: (x - x.mean()) / x.std()
)

# 组内填充均值
df['工资_组内补均值'] = grouped['工资'].transform(
    lambda x: x.fillna(x.mean())
)

# 常用内置 transform
df['工资_排名'] = grouped['工资'].transform('rank')          # 组内排名
df['工资_百分比'] = grouped['工资'].transform('pct_change')  # 组内变化率
df['工资_组均值'] = grouped['工资'].transform('mean')        # 组均值广播

agg vs transform 对比:

# agg 返回: 每个组一行
print(grouped['工资'].agg('mean'))     # shape: (3,)

# transform 返回: 与原 DataFrame 相同行数
print(grouped['工资'].transform('mean'))  # shape: (6,)

Filter — 组级筛选

# 保留组大小 >2 的组
filtered = grouped.filter(lambda g: len(g) > 2)

# 保留工资总和 > 20000 的组
filtered = grouped.filter(lambda g: g['工资'].sum() > 20000)

# 保留组内工资最大值 > 10000 的组
filtered = grouped.filter(lambda g: g['工资'].max() > 10000)

Apply — 最灵活的组操作

# apply 可以返回任意形状的 DataFrame/Series
def top_n(group, n=1):
    return group.nlargest(n, '工资')

result = grouped.apply(top_n, n=1)
print(result)

# 返回标量
result = grouped.apply(lambda g: g['工资'].max() - g['工资'].min())

# apply 可返回多列
def summary(g):
    return pd.Series({
        '人数': len(g),
        '平均工资': g['工资'].mean(),
        '工资范围': g['工资'].max() - g['工资'].min()
    })

result = grouped.apply(summary)
print(result)

其他分组方式

1. 按函数分组

# 按索引长度的奇偶分组
df.groupby(lambda idx: idx % 2 == 0).sum()

# 按工资是否 > 10000 分组
df.groupby(lambda idx: df.loc[idx, '工资'] > 10000).sum()

2. 按映射字典分组

mapping = {'张三': '组A', '李四': '组A', '王五': '组B',
           '赵六': '组B', '钱七': '组C', '孙八': '组C'}
df.groupby(mapping).sum()  # 注意: 按 index 映射
df.groupby(df['员工'].map(mapping)).sum()  # 按列值映射

3.groupby的as_index参数

# as_index=True (默认): 分组键作为索引
result = df.groupby('部门', as_index=True).sum()

# as_index=False: 分组键保留为列(类似 SQL group by)
result = df.groupby('部门', as_index=False).sum()

4. 多个groupby参数

# level: 按 MultiIndex 的层级分组
# axis: 按列分组 (axis=1)
# sort: 是否对组键排序(默认 True,设为 False 提升性能)
# dropna: 是否丢弃 NaN 组键(默认 True)
# observed: 分类数据是否只显示出现的组

# 性能优化设置
df.groupby('部门', sort=False, dropna=True)

实用分组技巧

累计操作

df['工资_累计和'] = grouped['工资'].cumsum()     # 组内累计和
df['工资_累计最大'] = grouped['工资'].cummax()   # 组内累计最大值
df['工资_累计积'] = grouped['工资'].cumprod()    # 组内累计积

组内偏移

df['工资_上一行'] = grouped['工资'].shift(1)        # 组内上移
df['工资_下一行'] = grouped['工资'].shift(-1)       # 组内下移
df['工资_变化'] = grouped['工资'].diff()             # 组内差分
df['工资_变化率'] = grouped['工资'].pct_change()     # 组内变化率

组内排名

df['工资排名'] = grouped['工资'].rank(method='dense', ascending=False)
# method: 'average', 'min', 'max', 'first', 'dense'

取每组的头/尾

df.groupby('部门').head(2)   # 每组前 2 行
df.groupby('部门').tail(1)   # 每组最后 1 行
df.groupby('部门').nth(0)    # 每组第 0 个
df.groupby('部门').nth([0, -1])  # 每组第 0 和最后一个
df.groupby('部门').nlargest(2, '工资')   # 每组工资最高的 2 行
df.groupby('部门').nsmallest(1, '奖金')  # 每组奖金最低的 1 行

抽样

df.groupby('部门').sample(n=1, random_state=42)     # 每组抽 1 个
df.groupby('部门').sample(frac=0.5, random_state=42) # 每组抽 50%

链式操作

# Pandas 支持方法链
result = (df
    .groupby('部门')
    .agg(总工资=('工资', 'sum'), 人数=('员工', 'count'))
    .query('人数 > 1')
    .sort_values('总工资', ascending=False)
    .reset_index()
)
print(result)

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • Python rstrip()方法实例详解

    Python rstrip()方法实例详解

    这篇文章主要介绍了Python rstrip()方法,包括rstrip方法的语法介绍和参数类型,需要的朋友可以参考下
    2018-11-11
  • python Django 创建应用过程图示详解

    python Django 创建应用过程图示详解

    这篇文章主要介绍了python Django 创建应用过程图示详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-07-07
  • python调用java的jar包方法

    python调用java的jar包方法

    今天小编就为大家分享一篇python调用java的jar包方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-12-12
  • python使用for...else跳出双层嵌套循环的方法实例

    python使用for...else跳出双层嵌套循环的方法实例

    这篇文章主要给大家介绍了关于python使用for...else跳出双层嵌套循环的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用python具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2020-05-05
  • Python Pyqt5多线程更新UI代码实例(防止界面卡死)

    Python Pyqt5多线程更新UI代码实例(防止界面卡死)

    这篇文章通过代码实例给大家介绍了Python Pyqt5多线程更新UI防止界面卡死的问题,代码简单易懂,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2021-12-12
  • python验证码识别教程之灰度处理、二值化、降噪与tesserocr识别

    python验证码识别教程之灰度处理、二值化、降噪与tesserocr识别

    这篇文章主要给大家介绍了关于python验证码识别教程之灰度处理、二值化、降噪与tesserocr识别的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考借鉴,下面随着小编来一起学习学习吧
    2018-06-06
  • 深入解析python返回函数和匿名函数

    深入解析python返回函数和匿名函数

    这篇文章主要介绍了python返回函数和匿名函数的相关知识,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-04-04
  • python中list循环语句用法实例

    python中list循环语句用法实例

    这篇文章主要介绍了python中list循环语句用法,以实例形式详细介绍了Python针对list的解析,包含各种常见的遍历操作及原理分析,需要的朋友可以参考下
    2014-11-11
  • 基于Python实现浪漫的弹窗祝福满屏飘字效果(附完整代码)

    基于Python实现浪漫的弹窗祝福满屏飘字效果(附完整代码)

    这篇文章主要为大家详细介绍了如何基于Python实现浪漫的弹窗祝福满屏飘字效果,文中的示例代码讲解详细,具有一定的借鉴价值,感兴趣的小伙伴可以了解下
    2026-01-01
  • Python 编程操作连载之字符串,列表,字典和集合处理

    Python 编程操作连载之字符串,列表,字典和集合处理

    这篇文章主要介绍了Python 编程操作连载之字符串,列表,字典和集合处理,文章围绕主题相关资料展开详细的内容介绍,需要的朋友可参考一下下面文章内容
    2022-06-06

最新评论