5-1 GroupBy分组会诊


文档摘要

5-1 GroupBy:分组会诊机制 本节摘要:GroupBy的机制是拆分、应用、合并三段——按键把表拆成若干子表,对每张子表做同样的操作,再把结果拼回来。本节讲透"组"这个数据形态,以及size、getgroup、groups三件探组器械。 数据出院后进入会诊室。管理层不要看三千行明细,要看"每家店怎么样"。把明细按门店拆开分别诊断再汇总会诊,就是GroupBy的全部思想。 三段机制拆解 groupby本身几乎不干活,它是"拆分方案的蓝图"。调用聚合函数那一刻,三段机制才开始:按门店的键把五拆成三张子表,每张子表求金额和,再按键拼回一张三行的小表。输出的索引就是分组键——这就是为什么第01章说Index是身份证:分组结果天然以键为索引。

5-1 GroupBy:分组会诊机制

本节摘要:GroupBy的机制是拆分、应用、合并三段——按键把表拆成若干子表,对每张子表做同样的操作,再把结果拼回来。本节讲透"组"这个数据形态,以及size、get_group、groups三件探组器械。

数据出院后进入会诊室。管理层不要看三千行明细,要看"每家店怎么样"。把明细按门店拆开分别诊断再汇总会诊,就是GroupBy的全部思想。

三段机制拆解

import pandas as pd df = pd.DataFrame({ '门店': ['A', 'A', 'B', 'B', 'C'], '渠道': ['线上', '线下', '线上', '线上', '线下'], '金额': [1280, 960, 1732, 880, 2100], }) grouped = df.groupby('门店') # 此刻还没算任何东西,只是建好分组档案 print(grouped) # <pandas.core.groupby.generic.DataFrameGroupBy object ...> print(grouped['金额'].sum()) # 门店 # A 2240 # B 2612 # C 2100

groupby本身几乎不干活,它是"拆分方案的蓝图"。调用聚合函数那一刻,三段机制才开始:按门店的键把五拆成三张子表,每张子表求金额和,再按键拼回一张三行的小表。输出的索引就是分组键——这就是为什么第01章说Index是身份证:分组结果天然以键为索引。

三件探组器械

# 器械一 size:每组的行数(不是计数和,是记录条数) print(grouped.size()) # 门店 # A 2 # B 2 # C 1 # 器械二 groups:查看每组的行号(诊断分组是否符合预期) print(grouped.groups) # {'A': [0, 1], 'B': [2, 3], 'C': [4]} # 器械三 get_group:单独请某组出来面谈 print(grouped.get_group('B')) # 门店 渠道 金额 # 2 B 线上 1732 # 3 B 线上 880

💡 关键直觉:写分组前先size一遍。组数是不是预期、每组行数是不是合理(某组只有一行多半是键没规范化,回4-3)——十秒钟的探组能省掉一份口径错误的报告。

多键分组与组内遍历

# 双键:门店-渠道两级会诊 multi = df.groupby(['门店', '渠道'])['金额'].sum() print(multi) # 门店 渠道 # A 线上 1280 # 线下 960 # B 线上 2612 # C 线下 2100 # unstack把内层键掀到列上(2-3的分层知识在这里兑现) print(multi.unstack('渠道')) # 渠道 线上 线下 # 门店 # A 1280 960.0 # B 2612 NaN ← C线上没开张,NaN而非0 # C NaN 2100.0 print(multi.unstack('渠道').fillna(0)) # 渠道 线上 线下 # 门店 # A 1280 960.0 # B 2612 0.0 # C 0 2100.0

组内遍历在调试时有用,但生产代码里几乎总有更好的写法:

for name, sub in grouped: print(name, '共', len(sub), '笔,均单', round(sub['金额'].mean(), 1)) # A 共 2 笔,均单 1120.0 # B 共 2 笔,均单 1306.0 # C 共 1 笔,均单 2100.0

拆分应用合并机制图

GroupBy三段机制

GroupBy三段机制

本节要点回顾

分组会诊还有一个工程细节值得交代:groupby默认把分组键从列收进索引(squeeze行为),加as_index=False可以让键留在普通列里,产出的结果直接是"键列加指标列"的平面表,省一次reset_index,交付给下游时更省心。这个参数在 notebooks 探索阶段无关痛痒,写进可复用的报表函数时就成了显著体验差异。

  • 三段机制:拆分按键成子表、应用同操作、合并按键回归
  • 分组结果是惰性的,groupby只是蓝图,聚合才执行
  • 探组三件:size看组量、groups看成员、get_group请单组面谈
  • 多键分组产生多层索引,unstack随时换排版
  • 没开张的组合是NaN不是0,报告前按口径fillna

追问:分组键的常见来源

真实数据里分组键不总是一列现成的字段。四种来源都值得熟悉:直接列(门店)、索引层(时间索引的月份,第07章的主角)、外部映射(每个门店属于哪个大区,字典或另一张表)、以及计算出来的键(金额分档)。最后一种在会诊里出现频率极高:

df['档位'] = pd.cut(df['金额'], bins=[0, 1000, 2000, float('inf')], labels=['小单', '中单', '大单']) print(df.groupby('档位', observed=True)['金额'].agg(['count', 'sum'])) # count sum # 档位 # 小单 2 1840 # 中单 2 2240 # 大单 1 2100

pd.cut把连续值切段成离散档,observed=True在category键上只显示实际出现的档(新版本默认行为,写上更稳)。金额分档加门店分组,两级会诊的维表就齐了。

追问:dropna与分组的关系

分组键里有缺失的行,groupby默认整组丢弃——又一个静默吞数据的点。真实数据里"渠道未知"的记录常常不少,直接分组等于假装它们不存在。两个选择:groupby(..., dropna=False)让缺失自成一组;或先fillna('未知')把缺失显式化再分组。后者更符合体检流水线的精神:缺失要被看见,而不是被技术细节蒸发。

dirty = pd.DataFrame({'渠道': ['线上', None, '线下'], '金额': [100, 200, 300]}) print(dirty.groupby('渠道', dropna=False)['金额'].sum()) # 渠道 # 线上 100 # 线下 300 # NaN 200 ← 被留在了会诊桌上

下一节讲应用段的三种输出形态:agg、transform与filter。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U