学径XUEJING · 个人学习平台通知设置

课程库 AI 主线 pandas 数据处理 › 第 6

分组与聚合 —— groupby:数据分析的核心动作

普通课60 分钟

本课导读

前五课都在"整理"数据,这课开始"拷问"数据:各城市卖了多少?每类产品平均单价?谁是销冠?——这类"按 X 分组看 Y"的问题是一切业务分析的原型,pandas 的答案叫 groupby。你其实早就手写过它(U0.4 的"遍历 + 字典计数"、U1.3 项目的分组归档),今天见它的终极形态:一行出结果。预计 60 分钟。

从手写分组到 groupby

先看你的老手艺,再看工业版——同一个问题:"各城市销售额合计":

Python

读法拆解 df.groupby("city")["amount"].sum(),三段式:

  1. groupby("city")——按城市把行分堆(上海一堆、北京一堆…)
  2. ["amount"]——每堆里只关心金额列
  3. .sum()——对每堆执行聚合(求和)

提示

类比记忆:groupby 是把一副扑克按花色分堆,再对每堆做同一件事(数张数、加点数、找最大)。口诀读作"按什么分、看什么列、算什么数"——任何 groupby 语句都能这么读出声。

聚合函数随便换:.sum() 合计、.mean() 平均、.count() 计数、.max()/.min() 极值。换着问几个问题:

Python

注意最后一招:groupby 的结果还是 Series/DataFrame,排序、head、筛选照常连招——流水线不断。

一次算多个指标:agg

老板从来不只问一个数:"各城市的总额、平均、单数都给我"——agg 一次交齐:

Python

agg(["sum", "mean", "count"])——把聚合函数名列成清单,一次全算。产出直接就是一张报表(round(1) 顺手控制小数位)。

多列分组:更细的切面

"每个城市每种产品卖了多少"——按两个维度分堆,groupby 收个列表就行:

Python

两个实用点:分组列表 ["city", "product"] 顺序即层级(先按城市、城市内再按产品);结果的"缩进式"行标签叫多级索引,看着费劲就 reset_index() 拍平成普通表——拍平之后又是熟悉的 DataFrame,接着筛选排序都随意。

value_counts 再登场:最快的"分组计数"

上节课的显微镜其实是 groupby 的特化快捷键——"按这列分组、数每组行数、降序排好":

Python

只是数次数就用 value_counts(还能一键出占比);要算金额等其他列才请 groupby——快捷键和全功能各有主场。

✍️ 练习

练习 1:口播翻译

把三句业务提问翻译成 groupby(用"按什么分、看什么列、算什么数"口诀):① 各部门平均工资 ② 各部门人数 ③ 各部门最高工资,并降序排列。

Python
✅ 参考答案
import pandas as pd

raw = """name,dept,salary
小雨,设计,12000
阿杰,运营,9500
丽丽,设计,13000
老王,销售,11000
小陈,运营,8800"""
with open("staff.csv", "w", encoding="utf-8") as f:
    f.write(raw)
df = pd.read_csv("staff.csv")

print(df.groupby("dept")["salary"].mean())
print(df.groupby("dept")["name"].count())
print(df.groupby("dept")["salary"].max().sort_values(ascending=False))

练习 2:一张报表交差

运营周会要一张表:各产品的销售总额、平均值、订单数,列名用中文,按总额降序。

Python
💡 提示

agg 三件套 → columns 改中文 → sort_values("总额", ascending=False)。

✅ 参考答案
import pandas as pd

raw = """order_id,product,amount
1001,键盘,299
1002,鼠标,178
1003,显示器,1599
1004,键盘,897
1005,鼠标,89
1006,键盘,598"""
with open("orders.csv", "w", encoding="utf-8") as f:
    f.write(raw)
df = pd.read_csv("orders.csv")

report = df.groupby("product")["amount"].agg(["sum", "mean", "count"])
report.columns = ["总额", "平均", "订单数"]
print(report.sort_values("总额", ascending=False).round(1))

练习 3:先洗后问(挑战)

真实节奏:这份数据带脏(城市空格、金额脏值)。先用上节课的流水线洗净,再回答"各城市有效销售总额,谁第一?"——洗和问必须在同一段代码里完成。

Python
✅ 参考答案
import pandas as pd

raw = """order_id,city,amount
1001, 上海,299
1002,北京 ,178
1003,上海,1599
1004,深圳,补录中
1005, 北京,89
1006,上海,918"""
with open("dirty_orders.csv", "w", encoding="utf-8") as f:
    f.write(raw)
df = pd.read_csv("dirty_orders.csv")

df["city"] = df["city"].str.strip()
df["amount"] = pd.to_numeric(df["amount"], errors="coerce")
df = df.dropna(subset=["amount"])

result = df.groupby("city")["amount"].sum().sort_values(ascending=False)
print(result)
print(f"销冠城市:{result.index[0]}")

不洗直接 groupby 的话:上海会分裂成两组、"补录中"直接让求和报错——清洗永远在分析前面,这是下一课项目和真实工作的铁律。

📝 随堂测验

随堂测验0 / 5 题正确

1. df.groupby("city")["amount"].sum() 的三段式读法是?

2. “各城市的总额、平均、订单数一次算齐”,用什么?

3. groupby(["city", "product"]) 结果的缩进式行标签看着费劲,怎么拍平?

4. 只想数“每个城市各有几行”,最快的写法是?

5. 对带脏数据的表直接 groupby 会发生什么?

本课小结

  • groupby 口诀:按什么分、看什么列、算什么数——df.groupby("列")["列"].sum()
  • 多指标 agg([...]) 出报表;多列分组出层级,reset_index() 拍平;结果可继续排序连招
  • 只数次数用 value_counts()(normalize 出占比);算账用 groupby
  • 铁律:清洗在分析前面——脏数据会被分组统计忠实放大

下一课把多张表"合体":订单表连上客户表——merge 与 concat,数据界的接亲家。

划选正文任意文字可高亮、批注或加入复习卡

讨论

载入中…