当前位置: 首页 > news >正文

别再手动分组了!Pandas分组聚合,让你的数据处理效率起飞

如果你经常和数据打交道,一定遇到过这样的场景:需要统计不同部门的平均工资,或者分析每个城市用户的购买习惯。这时候,你可能会下意识地想写一个 for 循环,一个个部门去处理。

如果数据量小,这么做勉强能忍。但如果数据有几十万行,这么写不仅代码冗长,效率还低得让人抓狂。

今天,我就带你彻底搞懂 Pandas 里最核心、最实用的功能之一——分组聚合。学完这一篇,你处理数据的速度至少提升10倍,而且代码会简洁到让同事惊呼“原来还能这样写”。


一、分组到底分了个啥?——先认识 GroupBy 对象

很多人一上来就着急写聚合函数,却忽略了理解 groupby 的本质。其实,当我们写下下面这行代码时:

import pandas as pd df = pd.read_csv("employees.csv") grouped = df.groupby("department_id")

grouped 并不是一个新的 DataFrame,而是一个DataFrameGroupBy 对象。你可以把它想象成一个“分组篮子”,它按照部门 ID 把原始数据分成了若干组,但此时并没有真正计算任何东西。这种设计叫做惰性计算,好处是节省内存,等你真正需要结果时,它才会动工。

你可以用 .groups 属性查看分组的内部结构:

print(grouped.groups)

运行后会看到一个字典,键是部门 ID,值是该部门所有行在原始 DataFrame 中的索引位置。

如果你想提取某个部门的数据,用 .get_group() 就可以了:

grouped.get_group(50) # 获取部门 50 的所有员工信息

二、分组后如何取值?——两种常用姿势

分组之后,我们通常只关心某些列,比如每个部门的薪资。有两种常见写法:

# 写法一:先分组,再取列 df.groupby("department_id")["salary"].mean() # 写法二:取列后分组(结果一样,写法更紧凑) df["salary"].groupby(df["department_id"]).mean()

两种写法最终都会得到一个SeriesGroupBy 对象,它代表的是按部门分组后的薪资序列。只有当你调用聚合函数(如 mean())时,Pandas 才会真正去计算平均值。

如果你想同时看多列,比如薪资和佣金率,就把列名放在列表里:

df.groupby("department_id")[["salary", "commission_pct"]].mean()

三、分组不止一个维度——按多个字段分组

现实业务中,按单个字段分组往往不够用。比如你想看每个部门里不同职位的平均薪资,这就需要按两个字段分组。

Pandas 实现起来非常直观,只需把字段名以列表形式传入即可:

result = df.groupby(["department_id", "job_id"])["salary"].mean() print(result)

你会发现,返回的结果有一个“复合索引”,看起来像两层的索引。如果觉得这种结构不方便后续操作,有两种方法可以把它变成普通列:

  • 方法一:用 .reset_index()
  • 方法二:在分组时加 as_index=False 参数
result = df.groupby(["department_id", "job_id"], as_index=False)["salary"].mean()

这两种方法都能得到一张干净整齐的表格。


四、把连续数据切成段——cut() 的妙用

有时候,我们需要把连续的数值(比如薪资)分成几个区间,再按区间去分析。这就是“分箱”操作,Pandas 的 cut() 函数专门干这个。

举个例子,把薪资分成高、中、低三档:

import pandas as pd df = pd.read_csv("employees.csv") salary_range = pd.cut(df["salary"], bins=3, labels=["低", "中", "高"]) print(salary_range)

cut() 的参数很好理解:

  • bins=3 表示分成三等份
  • labels 是自定义的标签

你也可以自己指定区间边界,比如把薪资分成 0-5000 和 5000-10000:

pd.cut(df["salary"], bins=[0, 5000, 10000])

分箱完成后,你就可以把分好的区间作为分组依据,进行更细致的分析。


五、聚合函数怎么用?——从基础到进阶

聚合是分组操作的重头戏。简单说,就是“每个组算出一个数”。

5.1 单列单函数

最常见的用法:

df.groupby("department_id")["salary"].mean()

这里的 mean() 可以换成 sum()、min()、max()、std()、count() 等,基本上你想到的统计函数它都有。

5.2 单列多函数

如果想一次算出多个统计值,用 .agg() 配合列表:

df.groupby("department_id")["salary"].agg(["min", "median", "max"])

这样会生成一个表格,每列对应一个统计函数,非常直观。

5.3 多列多函数(不同列用不同函数)

这是最灵活的场景。比如你想:

  • 对 salary 列求平均值和最大值
  • 对 commission_pct 列求平均值
  • 对 job_id 列统计不重复的职位个数

用字典形式传给 .agg() 即可:

result = df.groupby("department_id").agg({ "salary": ["mean", "max"], "commission_pct": "mean", "job_id": "nunique" })

5.4 自定义函数

如果内置函数不够用,你还可以自己写一个函数,传给 .agg()。比如,你想看每个部门里,所有员工的姓氏首字母有哪些:

def first_letters(x): return set(name[0] for name in x if pd.notna(name)) df.groupby("department_id")["last_name"].agg(first_letters)

六、分组后还能干点啥?——转换与过滤

除了聚合,分组操作还有两个高级玩法:转换和过滤。

6.1 转换(transform)——保持形状不变

transform() 的神奇之处在于,它返回的结果形状和原始数据一模一样

举个例子,你想给每个员工计算他“比部门平均薪资高多少”,可以这样写:

df["salary_diff"] = df.groupby("department_id")["salary"].transform(lambda x: x - x.mean())

这行代码会为每个员工生成一个值,表示他的薪资减去所在部门平均薪资。你不会看到任何“压缩”的效果,但每一行都有了自己在组内的相对位置。

另一个经典应用是按分组填充缺失值。比如,用部门平均薪资来填补该部门内缺失的薪资数据:

def fill_with_mean(x): return x.fillna(x.mean()) df["salary_filled"] = df.groupby("department_id")["salary"].transform(fill_with_mean)

6.2 过滤(filter)——按组整体筛选

有时你想保留某些组,剔除另一些组,这就要用到 filter()。

比如,你想只看那些有员工拿佣金的部门(即 commission_pct 列没有缺失值的部门):

filtered_df = df.groupby("department_id").filter(lambda x: x["commission_pct"].notnull().all())

filter() 会遍历每个分组,对每个分组执行你写的判断,返回 True 的分组保留,否则丢弃。


总结

Pandas 的分组功能远比我们想象的要强大。它不只是帮你“分组求和”,而是一整套数据处理的思维框架:

  • 分组对象是惰性的,只有调用函数时才会真正计算
  • 多字段分组帮你轻松实现多层次的分析维度
  • cut()让连续数据分箱变得无比简单
  • agg()能同时处理多列、多函数,甚至自定义函数
  • transform()保持形状不变,适合数据标准化和填充
  • filter()让你能按组整体筛选数据

掌握这些技巧之后,你会发现以前用循环才能做的事情,现在一行代码就能搞定。代码变短了,逻辑更清晰了,效率也上来了。

如果你还没在项目中用起来,不妨从今天开始,挑一个你以前用循环处理过的任务,用 Pandas 分组重写一遍。相信我,那种“丝滑”的感觉,会让你彻底爱上这种编程方式。


如果这篇文章对你有帮助,欢迎点赞、收藏、转发,也欢迎在评论区交流你遇到的分组问题,我们一起探讨更优雅的解法!

http://www.jsqmd.com/news/571139/

相关文章:

  • MATLAB bertool实战:从Simulink建模到误码率曲线对比分析
  • 算法优化赋能忍者像素绘卷:提升图像生成速度与质量的实用技巧
  • 学Simulink——基于Simulink的能耗最优PMSM轨迹跟踪与再生制动仿真
  • AI赋能机器人抓取:在快马平台探索OpenClaw Onboard与强化学习的结合
  • 定制AI视觉扫描仪优选锯厂家怎么选,有哪些品牌值得考虑? - 工业设备
  • Claude Code 源码泄露!5 分钟搭建本地离线 AI 程序员,免费无 API 费用
  • OpenCore Legacy Patcher终极指南:让旧Mac焕发新生的完整解决方案
  • AI模型交响乐:在快马平台组合多模型打造更聪明的旗博士口播智能体
  • BilibiliDown高效视频下载全攻略:3分钟解决B站离线观看难题
  • 如何在 Windows 11/10 电脑上永久删除文件
  • 2026年微信公众号编辑器深度测评:8款主流工具实测与选型 - 行业产品测评专家
  • 91160-cli智能预约助手:医疗资源高效获取的全自动化解决方案
  • 快速体验:Xinference-v1.17.1在Jupyter中加载Phi-3-mini模型,5分钟出结果
  • 如何优化网站内容提高排名_站内搜索优化对网站SEO有什么影响
  • Text-to-SQL 没有答错,但答案不一定是你要的那个
  • Dota全图透视辅助DOTA全图外挂透视辅助使用人群及五大对战平台现状分析
  • Linux 与 Shell 自动化运维基础知识记录
  • 全国各省市医院妇产科全面启用《出生医学证明》人证核验系统 - 智能硬件-产品评测
  • Univer全栈框架:企业级电子表格协作系统的架构设计与技术实现
  • 2026年国内优质的非标链条品牌选哪家,不锈钢链条/非标链条/工业链条/链条,非标链条直销厂家选哪家 - 品牌推荐师
  • AI绘画新手必看:Nunchaku FLUX.1-dev在ComfyUI中的简单应用
  • Nunchaku-flux-1-dev与ComfyUI集成:可视化工作流搭建指南
  • 如何通过N-bit ADC的过采样与噪声整形优化SQNR性能
  • FLUX.2-Klein-9B-NVFP4实战:5分钟学会图片换装,效果超自然
  • 讲讲AI视觉扫描仪优选锯,浙江地区哪家厂家支持个性化定制且口碑好 - myqiye
  • Ollama助力Llama-3.2-3B落地:快速部署教程与实用功能体验分享
  • AI 编码浪潮下:优质代码能否战胜代码冗余?
  • 别再死记硬背了!用MATLAB仿真带你直观理解MSK:从相位连续到三种解调原理
  • html-to-docx架构解析:构建高性能HTML到Word文档转换引擎
  • 配网接地故障排查效率提升3倍:力兴电子LX6180交流试送仪