Pythongroupby数据聚合详解
“纵有疾风来,人生不言弃”,这句话送给正在学习文章的朋友们,也希望在阅读本文《Python数据聚合:groupby方法详解》后,能够真的帮助到大家。我也会在后续的文章中,陆续更新文章相关的技术文章,有好的建议欢迎大家在评论留言,非常感谢!
groupby方法是Python中pandas库实现数据聚合的核心工具。1. 它基于“分、应用、合”(Split-Apply-Combine)的思想,将数据按一个或多个键拆分成组,对每组独立执行聚合操作如求和、计数、平均值等。2. 使用时通常需要一个DataFrame,并指定分组键,例如可计算每个地区的总销售额或每种产品在不同地区的平均销售额。3. 支持多列聚合、自定义聚合函数及命名聚合,提升灵活性与结果可读性。4. 在处理大规模数据时需注意内存消耗、聚合函数选择及分组键的数据类型优化,必要时可采用分布式框架。5. 高级用法包括transform()进行数据变换、filter()筛选组数据及apply()实现复杂逻辑,分别对应不同的应用场景。6. 与SQL的GROUP BY相比,核心理念一致但语法和功能有所差异,groupby更灵活且支持更多高级操作,同时可通过reset_index()等方法实现SQL等效查询。
Python中实现数据聚合,pandas
库的groupby
方法是核心工具,它允许你根据一个或多个键将数据拆分成组,然后对每个组独立地执行聚合操作,比如求和、计数、平均值等,极大简化了复杂数据分析。它不仅仅是简单的数据汇总,更是一种“分而治之”的思维体现,能帮助我们从数据中挖掘出更深层次的洞察。

解决方案
pandas
的groupby
方法是处理聚合任务的瑞士军刀。要使用它,你通常需要一个DataFrame,然后指定一个或多个列作为分组的键。

想象一下,我们有一份销售数据,包含了产品、地区和销售额。如果我想知道每个地区总共卖了多少钱,或者每种产品在不同地区的平均销售额,groupby
就能派上大用场。
import pandas as pd import numpy as np # 模拟一份销售数据 data = { '地区': ['华东', '华南', '华东', '华北', '华南', '华东', '华北', '华南'], '产品': ['A', 'B', 'A', 'C', 'B', 'C', 'A', 'A'], '销售额': [100, 150, 120, 80, 200, 90, 110, 130], '销量': [10, 15, 12, 8, 20, 9, 11, 13] } df = pd.DataFrame(data) print("原始数据:") print(df) print("-" * 30) # 最基础的用法:按“地区”分组,计算每个地区的总销售额 print("按地区计算总销售额:") region_sales = df.groupby('地区')['销售额'].sum() print(region_sales) print("-" * 30) # 多列聚合:按“地区”和“产品”分组,计算销售额总和与销量平均值 print("按地区和产品计算销售额总和与销量平均值:") multi_agg = df.groupby(['地区', '产品']).agg({ '销售额': 'sum', '销量': 'mean' }) print(multi_agg) print("-" * 30) # 也可以对多个列应用同一个聚合函数 print("对多个列应用同一个聚合函数:") multi_col_same_agg = df.groupby('地区')[['销售额', '销量']].sum() print(multi_col_same_agg) print("-" * 30) # 自定义聚合函数:例如,计算每个地区销售额的标准差 print("自定义聚合函数(销售额标准差):") region_std = df.groupby('地区')['销售额'].apply(lambda x: np.std(x, ddof=1)) # ddof=1 for sample standard deviation print(region_std) print("-" * 30) # 命名聚合:让聚合结果列名更清晰 print("命名聚合:") named_agg = df.groupby('地区').agg( 总销售额=('销售额', 'sum'), 平均销量=('销量', 'mean'), 销售额计数=('销售额', 'count') ) print(named_agg) print("-" * 30)
groupby
的核心在于“分、应用、合”(Split-Apply-Combine)这个思想。它首先根据你指定的键将数据“拆分”成若干个独立的小组,然后对每个小组独立地“应用”一个函数(比如求和、求平均、自定义函数),最后将这些独立计算的结果“合并”成一个新的DataFrame或Series。这个过程,在我看来,是数据分析中非常优雅且高效的模式。

groupby
在处理大规模数据集时有哪些性能考量?
当我们面对GB甚至TB级别的数据时,groupby
的性能就不仅仅是“能用”的问题了,而是“能否高效地用”的问题。我个人在处理大表时,确实遇到过一些性能瓶颈,总结下来有几点值得注意。
首先,内存消耗是个大头。groupby
在内部需要创建一些中间对象来存储分组信息和临时计算结果。如果分组的键(比如用户ID、时间戳)非常多且唯一值数量巨大,或者每个组的数据量都很大,内存占用会迅速飙升。有时候,一个看似简单的groupby
操作,可能导致内存溢出。
其次,聚合函数的选择也影响性能。内置的聚合函数(如sum()
, mean()
, count()
, min()
, max()
)通常是用C语言实现的,效率极高。但如果你频繁使用apply()
方法配合Python自定义函数进行聚合,性能可能会大幅下降。因为apply()
在每个组上都会调用Python解释器,这会带来额外的开销。如果可以,尽量用内置函数或NumPy函数。
再者,分组键的数据类型也很关键。如果你的分组键是字符串,尤其是长字符串,那么比较和哈希操作会相对较慢。将字符串列转换为category
类型(分类类型)可以显著提升groupby
的性能和减少内存占用,因为category
类型在内部存储的是整数编码,而不是实际的字符串。这在处理像省份、城市、产品类别这类有限且重复性高的字符串时尤其有效。
# 示例:将字符串列转换为category类型 df_large = pd.DataFrame({ '城市': np.random.choice(['北京', '上海', '广州', '深圳', '杭州', '成都'], 1000000), '销售额': np.random.rand(1000000) * 1000 }) # 转换前 print("转换前数据类型:", df_large['城市'].dtype) %timeit df_large.groupby('城市')['销售额'].sum() # 转换后 df_large['城市'] = df_large['城市'].astype('category') print("转换后数据类型:", df_large['城市'].dtype) %timeit df_large.groupby('城市')['销售额'].sum()
(注:上述%timeit
需要在Jupyter或IPython环境中运行才能看到效果,这里仅作示例说明)
此外,如果你的数据量真的非常庞大,超出了单机内存限制,那么你可能需要考虑Dask、Spark等分布式计算框架,它们提供了与pandas
类似的API,但能在集群上并行处理数据。不过,这已经超出了pandas
本身的范畴了。
除了基础聚合,groupby
还能实现哪些高级数据变换?
groupby
的魅力远不止于简单的sum
或mean
。它还有几个非常强大的伴侣方法,能让你在分组的基础上进行更复杂的数据变换和筛选,它们是transform()
、filter()
和apply()
。
transform()
方法非常独特。它在分组后应用一个函数,然后将结果“广播”回原始DataFrame的形状。这意味着输出的Series或DataFrame的索引和原始数据是完全对齐的。这对于填充缺失值、标准化数据或计算组内排名等场景非常有用。
比如,我想填充每个地区的平均销售额到该地区缺失的销售额记录中,或者我想计算每个销售额在其所属地区的Z-score(标准化分数),transform
就是不二之选。
# 示例:使用transform进行组内标准化(Z-score) df_transform = pd.DataFrame({ '地区': ['华东', '华南', '华东', '华北', '华南', '华东', '华北', '华南'], '销售额': [100, 150, 120, 80, 200, 90, 110, 130] }) # 计算每个地区销售额的Z-score df_transform['销售额_Zscore'] = df_transform.groupby('地区')['销售额'].transform(lambda x: (x - x.mean()) / x.std(ddof=1)) print("使用transform进行组内标准化:") print(df_transform) print("-" * 30)
filter()
方法则用于筛选整个组。它接收一个函数,这个函数对每个组返回一个布尔值(True或False)。如果返回True,则保留该组的所有行;如果返回False,则丢弃该组的所有行。这对于只分析满足特定条件的组非常有用。
例如,我只想看那些销售额总和超过某个阈值的地区的数据,或者只保留那些至少有N个产品的地区。
# 示例:使用filter筛选销售额总和大于300的地区 print("使用filter筛选销售额总和大于300的地区:") filtered_df = df.groupby('地区').filter(lambda x: x['销售额'].sum() > 300) print(filtered_df) print("-" * 30)
注意看,filter
返回的是原始DataFrame的子集,保留了符合条件的整个组的数据。
最后是apply()
,它是groupby
家族中最灵活的。它允许你将任何函数应用到每个分组上,这个函数可以返回一个标量、一个Series、一个DataFrame,甚至是一个列表。apply()
的强大之处在于它的通用性,你可以用它来完成transform
和filter
无法直接实现,或者需要更复杂逻辑的操作。
比如,我想对每个地区的数据进行某种模型预测,或者计算每个地区的某个复杂指标,apply()
就能派上用场。但正如前面提到的,它的性能开销通常比内置函数或transform
大。
# 示例:使用apply计算每个地区销售额的“销售额/销量”平均值(假设这是个复杂指标) # 注意:这里为了演示apply的灵活性,实际操作中可能直接计算再聚合 def custom_metric(group): # 假设我们想计算每个组的销售额和销量的比率的平均值 if group['销量'].sum() == 0: return 0 return (group['销售额'] / group['销量']).mean() print("使用apply进行自定义复杂指标计算:") custom_agg = df.groupby('地区').apply(custom_metric) print(custom_agg) print("-" * 30)
理解这三者的区别和适用场景,能让你在数据处理时更加游刃有余。简单来说,需要广播结果回原始形状用transform
,需要根据组的特性筛选组用filter
,而需要对每个组执行任意复杂逻辑则用apply
。
groupby
与SQL中的GROUP BY
有什么异同?如何进行等效操作?
作为一名数据分析师,我经常在Python和SQL之间切换,自然会思考它们在数据聚合上的异同。pandas
的groupby
和SQL的GROUP BY
在核心理念上是高度一致的,都是基于“分而治之”的思想,将数据按指定键分组,然后对每个组执行聚合操作。但它们在语法和某些高级功能上还是有些区别。
共同点:
- 核心功能: 都是用来进行数据聚合,比如计算总和、平均值、计数、最大值、最小值等。
- 分组键: 都支持按一个或多个列进行分组。
- 聚合函数: 都提供了一系列内置的聚合函数。
不同点:
输出形式:
- SQL的
GROUP BY
通常要求SELECT
语句中除了聚合列,其他列必须是分组键。结果是一个新的、行数减少的表。 pandas
的groupby
默认会将分组键作为结果DataFrame的索引(或多级索引)。它对非聚合列的处理更灵活,你可以选择性地聚合它们,或者在后续操作中通过reset_index()
将其变回普通列。
- SQL的
高级功能:
pandas
的groupby
提供了transform()
和filter()
这两个SQL中没有直接对应但功能强大的方法。transform()
可以实现类似SQL窗口函数(Window Functions)的部分功能,比如计算组内排名或填充组内平均值。filter()
则可以实现SQL的HAVING
子句功能,但更灵活。- SQL有更丰富的窗口函数,例如
ROW_NUMBER()
,LAG()
,LEAD()
等,这些在pandas
中通常需要结合groupby().transform()
或更复杂的逻辑来实现。
自定义函数:
pandas
的apply()
方法允许你将任意Python函数应用到每个组,这在SQL中实现自定义聚合函数通常需要编写用户定义函数(UDF),相对复杂一些。
等效操作:
我们来看几个常见的SQL GROUP BY
操作如何用pandas
实现。
场景1:计算每个地区总销售额
- SQL:
SELECT 地区, SUM(销售额) AS 总销售额 FROM 销售表 GROUP BY 地区;
- Pandas:
region_sales_pd = df.groupby('地区')['销售额'].sum().reset_index() print("Pandas等效SQL查询1:") print(region_sales_pd) print("-" * 30)
场景2:计算每个地区和产品的平均销售额和总销量
- SQL:
SELECT 地区, 产品, AVG(销售额) AS 平均销售额, SUM(销量) AS 总销量 FROM 销售表 GROUP BY 地区, 产品;
- Pandas:
multi_agg_pd = df.groupby(['地区', '产品']).agg( 平均销售额=('销售额', 'mean'), 总销量=('销量', 'sum') ).reset_index() print("Pandas等效SQL查询2:") print(multi_agg_pd) print("-" * 30)
场景3:筛选出总销售额超过200的地区
- SQL (使用HAVING):
SELECT 地区, SUM(销售额) AS 总销售额 FROM 销售表 GROUP BY 地区 HAVING SUM(销售额) > 200;
- Pandas (使用filter):
filtered_region_pd = df.groupby('地区').filter(lambda x: x['销售额'].sum() > 200) # 如果只想看聚合结果,可以先filter再聚合 # filtered_region_agg_pd = filtered_region_pd.groupby('地区')['销售额'].sum().reset_index() print("Pandas等效SQL查询3 (使用filter):") print(filtered_region_pd) # filter返回原始数据 print("-" * 30)
可以看到,pandas
的groupby
在很多情况下提供了与SQL GROUP BY
相似甚至更灵活的功能。理解它们之间的映射关系,能帮助我们更流畅地在不同工具间切换,并选择最适合当前任务的实现方式。在我看来,掌握groupby
的各种高级用法,是真正发挥pandas
数据处理能力的关键一步。
今天关于《Pythongroupby数据聚合详解》的内容就介绍到这里了,是不是学起来一目了然!想要了解更多关于groupby,数据聚合,filter,transform,Pandas的内容请关注golang学习网公众号!

- 上一篇
- Python正则入门:re模块使用教程

- 下一篇
- PhpStorm远程调试设置全攻略
-
- 文章 · python教程 | 27秒前 |
- PyCharm图形界面显示问题解决方法
- 231浏览 收藏
-
- 文章 · python教程 | 2分钟前 |
- Pythonjieba分词教程详解
- 439浏览 收藏
-
- 文章 · python教程 | 5分钟前 |
- Python异常处理技巧:try-except使用教程
- 119浏览 收藏
-
- 文章 · python教程 | 8分钟前 |
- PyCharm找不到解释器?路径设置全教程
- 238浏览 收藏
-
- 文章 · python教程 | 12分钟前 |
- Python中-=运算符的使用方法
- 157浏览 收藏
-
- 文章 · python教程 | 13分钟前 |
- Python代码格式化工具推荐
- 182浏览 收藏
-
- 文章 · python教程 | 21分钟前 |
- PyCharm安装教程手把手教学流程
- 237浏览 收藏
-
- 文章 · python教程 | 35分钟前 |
- Python入门必备代码大全
- 386浏览 收藏
-
- 文章 · python教程 | 44分钟前 |
- Python用Prophet做市场预测方法
- 480浏览 收藏
-
- 文章 · python教程 | 47分钟前 |
- Python项目打包与发布全攻略
- 112浏览 收藏
-
- 文章 · python教程 | 48分钟前 |
- Python数据聚类方法与sklearn实战解析
- 110浏览 收藏
-
- 文章 · python教程 | 1小时前 |
- Python高阶函数实用场景解析
- 451浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 542次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 508次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 497次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 484次学习
-
- 免费AI认证证书
- 科大讯飞AI大学堂推出免费大模型工程师认证,助力您掌握AI技能,提升职场竞争力。体系化学习,实战项目,权威认证,助您成为企业级大模型应用人才。
- 32次使用
-
- 茅茅虫AIGC检测
- 茅茅虫AIGC检测,湖南茅茅虫科技有限公司倾力打造,运用NLP技术精准识别AI生成文本,提供论文、专著等学术文本的AIGC检测服务。支持多种格式,生成可视化报告,保障您的学术诚信和内容质量。
- 160次使用
-
- 赛林匹克平台(Challympics)
- 探索赛林匹克平台Challympics,一个聚焦人工智能、算力算法、量子计算等前沿技术的赛事聚合平台。连接产学研用,助力科技创新与产业升级。
- 211次使用
-
- 笔格AIPPT
- SEO 笔格AIPPT是135编辑器推出的AI智能PPT制作平台,依托DeepSeek大模型,实现智能大纲生成、一键PPT生成、AI文字优化、图像生成等功能。免费试用,提升PPT制作效率,适用于商务演示、教育培训等多种场景。
- 179次使用
-
- 稿定PPT
- 告别PPT制作难题!稿定PPT提供海量模板、AI智能生成、在线协作,助您轻松制作专业演示文稿。职场办公、教育学习、企业服务全覆盖,降本增效,释放创意!
- 169次使用
-
- Flask框架安装技巧:让你的开发更高效
- 2024-01-03 501浏览
-
- Django框架中的并发处理技巧
- 2024-01-22 501浏览
-
- 提升Python包下载速度的方法——正确配置pip的国内源
- 2024-01-17 501浏览
-
- Python与C++:哪个编程语言更适合初学者?
- 2024-03-25 501浏览
-
- 品牌建设技巧
- 2024-04-06 501浏览