3.4 分组聚合与合并连接


3.4 分组聚合与合并连接

本节摘要:分组聚合(groupby)是 Pandas 分析能力的核心——"按门店统计销售额"这类需求一行代码搞定;合并连接(merge/concat)则解决"数据散在多张表"的问题。本节讲透 groupby 的分组-聚合-变换三段式,以及 merge 的四种连接方式。

本节目标

阅读完本节,你应当能够:

  1. 用 groupby 按单列、多列分组并聚合统计
  2. 用 agg 同时计算多个统计量,用 groupby 加 transform 做组内变换
  3. 用 merge 完成内连接、左连接等四种连接
  4. 用 concat 拼接 DataFrame
  5. 完成"订单表 + 门店表"的跨表分析

一、问题与直觉

"这家店这个月卖了多少""哪个类目贡献了最多收入"——这类问题每天都会问。如果靠手工筛选,每个门店写一遍代码,十个门店十段重复。groupby 把"按 XX 分组 → 对每组算 YY"封装成一个动作,一句代码完成全部组别的统计。

另一个高频场景是数据不在同一张表:订单表里有门店编号,门店信息(城市、负责人)在另一张表里。把它们拼起来,才能回答"哪个城市的订单最多"——这就是 merge 和 concat 的用武之地。

二、核心原理

2.1 groupby 的三段式

groupby 与 merge 解决两类不同的问题——"组内汇总"与"跨表拼接":

groupby 操作本质分三步:拆分(按分组键把行分成若干组)→ 应用(对每组执行聚合或变换)→ 合并(把结果拼回)。理解"拆-算-合"模型,就不会被眼花缭乱的 groupby 写法绕晕。

import pandas as pd df = pd.DataFrame({ "门店": ["北京", "上海", "北京", "广州", "北京"], "类目": ["数码", "数码", "家电", "家电", "服装"], "金额": [199, 355, 89, 1299, 450], }) # 按门店分组,算每组的销售额总和 df.groupby("门店")["金额"].sum() # 按门店+类目分组,算每组均值 df.groupby(["门店", "类目"])["金额"].mean()

2.2 聚合与变换

agg 一次算多个统计量;transform 把组内统计广播回每一行(行数不变),常用于"计算每行相对组均值的偏差":

df.groupby("门店")["金额"].agg(["sum", "mean", "count"]) # transform:每行得到所在组的均值 df["组均值"] = df.groupby("门店")["金额"].transform("mean") df["偏差"] = df["金额"] - df["组均值"]

💡 关键直觉:agg 压缩行数(每组一行结果),transform 保持行数(结果广播回原表)。想"分组后比较每行与组内水平"就用 transform。

2.3 merge:按键连接两张表

merge 类似 SQL 的 JOIN,四种连接方式决定结果的取舍:

orders = pd.DataFrame({ "订单号": ["A001", "A002", "A003"], "门店编号": [1, 2, 1], "金额": [199, 355, 89], }) stores = pd.DataFrame({ "门店编号": [1, 2, 3], "城市": ["北京", "上海", "广州"], }) pd.merge(orders, stores, on="门店编号") # 内连接:只留两边都有的 pd.merge(orders, stores, on="门店编号", how="left") # 左连接:保留订单全部行 pd.merge(orders, stores, on="门店编号", how="right") # 右连接:保留门店全部行 pd.merge(orders, stores, on="门店编号", how="outer") # 外连接:全保留,缺的填 NaN

2.4 连接方式速查

how 参数 保留哪些行 典型用途
inner(默认) 键两边都有的 只分析能对上号的数据
left 左表全部 订单为主,补门店信息
right 右表全部 门店为主,看哪些无订单
outer 全部,缺的填 NaN 盘点全量对账

2.5 concat:上下拼接

jan = pd.DataFrame({"门店": ["北京"], "销售额": [120]}) feb = pd.DataFrame({"门店": ["上海"], "销售额": [150]}) pd.concat([jan, feb], ignore_index=True) # 上下拼接(行方向) pd.concat([df1, df2], axis=1) # 左右拼接(列方向)

三、工程实践要点

3.1 多列分组与透视

# 按门店+日期分组汇总 summary = df.groupby(["门店", "日期"])["金额"].sum().reset_index() # 透视:行=门店,列=类目,值=金额和 pivot = df.pivot_table(index="门店", columns="类目", values="金额", aggfunc="sum")

reset_index() 把分组键从索引变回普通列,是分组后接续操作的标准动作。pivot_table 则是"分组聚合的表格化展示",一眼看出交叉汇总。

3.2 合并后的检查

merged = pd.merge(orders, stores, on="门店编号", how="left") print(merged.isnull().sum()) # 检查左连接后有没有对不上的门店

⚠️ 常见坑:merge 后出现大量 NaN,多半是键值对不上(门店编号 3 没有订单)。先 isnull().sum() 查缺失,再回源表看键值差异,别急着填数。

3.3 贯穿案例:跨表分析门店销售

把订单表和门店表合并,回答"各城市的订单总额":

import pandas as pd orders = pd.DataFrame({ "订单号": ["A001", "A002", "A003", "A004"], "门店编号": [1, 2, 1, 3], "金额": [199, 355, 89, 1299], }) stores = pd.DataFrame({ "门店编号": [1, 2, 3], "城市": ["北京", "上海", "广州"], "负责人": ["王", "李", "张"], }) merged = pd.merge(orders, stores, on="门店编号", how="left") result = merged.groupby("城市")["金额"].sum().sort_values(ascending=False) print(result)

输出就是各城市销售额从高到低的排名——一条完整链路:合并补信息 → 分组聚合 → 排序出结论。

3.4 性能与习惯

  • 分组键用 category 类型可显著加速 groupby
  • 大表 merge 前先确认键的类型一致(int 对 object 会慢且容易错)
  • 频繁对同一 DataFrame 分组,把结果存起来复用,别反复重算

3.5 分组后索引的两种形态

groupby 的返回结果,索引与列的形态有两种:

# 形态一:分组键留在索引里 s = df.groupby("门店")["金额"].sum() # 门店 是索引,金额 是值 # 形态二:分组键还原成普通列 df2 = s.reset_index() # 门店、金额 都是列

💡 关键直觉:聚合结果默认把分组键放在索引上。要继续 merge 或参与后续表格操作,先 reset_index() 把键还原成列——这是分组后最常见的第一步。

3.6 聚合函数对比

聚合函数 用途 注意
sum 总和 默认跳过 NaN
mean 均值 受异常值影响
median 中位数 抗异常值
count 非空计数 不含 NaN
nunique 唯一值数 常用于"有多少客户"
first / last 首末值 保留上下文
agg(["sum", "mean"]) 多统计量 一次算多个

"每个门店有多少个不同客户"这类需求,用 nunique 一句话搞定:df.groupby("门店")["客户号"].nunique()

3.7 复杂变换:分组后的组内排名

# 每个门店内按金额排名(1 为最高) df["门店内排名"] = df.groupby("门店")["金额"].rank(ascending=False) # 每个门店销售额占比 df["门店占比"] = df.groupby("门店")["金额"].transform( lambda x: x / x.sum() )

组内排名、组内占比是业务分析高频操作,都建立在 groupby 的"拆-算-合"模型上——想清楚"按什么拆、每组算什么、结果放哪",一切分组操作都不难。

3.8 合并易错点排查

现象 原因 排查方法
合并后行数暴增 键有重复,笛卡尔积 drop_duplicates(subset=[键])
合并后大量 NaN 键值对不上 isnull().sum() + 看两表唯一值
键列名不同 on 指定错误 left_on / right_on 分别指定
类型不一致 int 对 object astype 统一后再 merge

⚠️ 常见坑:merge 前不查重复键,是"合并后数据莫名其妙翻倍"的头号原因。两个表里都有重复的门店编号时,merge 会把它们两两配对——先对键去重,再合并。

重点提炼

  • 要点一:groupby 是"拆-算-合"三段式,groupby(键)[列].agg() 是标准句式
  • 要点二:agg 压缩行数、transform 广播回行,按需求二选一
  • 要点三:merge 四种连接——inner/left/right/outer,业务主表决定 how
  • 要点四:concat 上下拼接数据行,axis=1 变左右拼接
  • 要点五pivot_table 把分组结果变成交叉表,一目了然
  • 要点六:merge 后先 isnull().sum() 查对不上的键,别急着填

Pandas 的核心能力到这就齐了。下一章我们把这些技能系统化,专门对付"脏数据"——数据清洗与预处理。


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