Python 环境加载中…

分组汇总与透视表

3 道练习题·预计 45 分钟·做对一题解锁下一段

完整通读本章 →

教学 01 / 08· 已读

前言

还记得第 1 章那三行 pandas 代码吗?其中有一个 groupby() ,按类别把金额加了起来。不过当时只说了它能做什么,并没有细讲。

这一章,咱们就把它讲透。为什么值得专门花一章来讲呢?因为「每个类别花了多少」「每个月花了多少」「每个月、每个类别各花了多少」,这类问题在数据分析里最常见。而且仔细想想,它们其实都是同一个套路:按某一列分组,每组算一个数,再拼成一张表。

第 4 章里,咱们用 for 循环,把一日三餐挨个算了一遍。学完这一章,这种事一行代码就能做完。

学这一章之前,需要先学完 数据分析课第 5 章 。

目录

这一章会学到:

  • 一、分组汇总——groupby() 在做什么
  • 二、一次算好几个数——agg() ,按结果排序
  • 三、按月汇总——用上日期
  • 四、两个方向一起分——pivot_table()
  • 五、常见坑
  • 六、自己查一次文档——给透视表加上合计
  • 七、小结与回看

学完这一章,记账本里任何「每个……花了多少」的问题,你都能用一两行代码算出来。

教学 02 / 08· 已读

一、分组汇总

groupby() 到底做了些什么呢?咱们先回到第 1 章的那一行,把它单独拿出来看:

Python· 可在网页运行
import pandas as pd

ledger = pd.read_csv('ledger_2026.csv')
print(ledger.groupby('category')['cost'].sum())

输出的结果:

文本
category
交通     1713.0
医疗     1181.5
娱乐     3178.0
学习     1659.0
居住    32888.5
购物     4992.5
餐饮    23583.0
Name: cost, dtype: float64

别看只有一行,它其实做了三件事:

  1. 分:groupby('category') 按类别,把一千多行分成 7 堆:交通一堆,医疗一堆……
  2. 算:['cost'].sum() 从每一堆里各自取出金额,加起来。
  3. 合:把 7 个结果拼成一个 Series,类别就成了左边的索引。

你也许注意到了,结果是按类别的名字排的,而不是按金额。这是因为 groupby() 默认会把分组的名字排好序。想按金额排,后面再接一个 sort_values() 就行,第 1 章就是这么做的。

那么,「算」这一步只能求和吗?当然不是,换成别的方法也行。下面这段代码,就换了两种算法:

Python· 可在网页运行
import pandas as pd

ledger = pd.read_csv('ledger_2026.csv')
print(ledger.groupby('item')['cost'].mean().round(2).head(4))
print(ledger.groupby('category').size())

输出的结果:

文本
item
书       59.81
午饭     26.40
咖啡     22.24
唱歌    105.23
Name: cost, dtype: float64
category
交通    241
医疗      7
娱乐     46
学习     11
居住     36
购物     29
餐饮    984
dtype: int64

上面打印了两个结果,咱们分开来看:

  • 前一个是按名称分组,再求平均,算的是每种花销平均一笔多少钱。第 4 章用 for 循环才算出三餐的平均,这里一行就全算出来了。
  • 后一个用的是 size() ,它数的是每一组有几行,所以不用取哪一列。结果和第 4 章的 value_counts() 一样,只是按名字排了序。

总结一下就是:groupby() 后面接什么方法,每一组就算什么。sum() 、mean() 、median() 、max() 、count() ……前几章学过的这些,在这里都能用。

不过到现在为止,每次都只算了一个数。要是想同时看好几个数呢?下一节就来解决。

教学 03 / 08

二、一次算好几个数

上一节,groupby() 后面每次只接一个方法,一次只算一个数。可真正分析的时候,常常想同时知道好几个数。比如每个类别,既想知道记了几笔,又想知道合计和平均。

分三次写,当然也能算出来,就是太啰嗦了。这时候可以用 agg() ,一次全算完。用法是在括号里放一个列表,列表里写上要用的方法名:

Python· 可在网页运行
import pandas as pd

ledger = pd.read_csv('ledger_2026.csv')
summary = ledger.groupby('category')['cost'].agg(['count', 'sum', 'mean']).round(2)
print(summary)

输出的结果:

文本
          count      sum    mean
category                        
交通        241   1713.0    7.11
医疗          7   1181.5  168.79
娱乐         46   3178.0   69.09
学习         11   1659.0  150.82
居住         36  32888.5  913.57
购物         29   4992.5  172.16
餐饮        984  23583.0   23.97

和上一节比一比,结果有什么不一样?上一节只算一个数,结果是一个 Series。这回算了好几个数,结果就成了一张 DataFrame:每个方法占一列,列名就是方法名。

不过,这张表是按类别的名字排的,谁多谁少看不出来。要是按合计排一下序,就好读多了。要注意的是,DataFrame 有好几列,所以它的 sort_values() 得说明按哪一列来排:

Python· 可在网页运行
import pandas as pd

ledger = pd.read_csv('ledger_2026.csv')
summary = ledger.groupby('category')['cost'].agg(['count', 'sum', 'mean']).round(2)
print(summary.sort_values('sum', ascending=False))

输出的结果:

文本
          count      sum    mean
category                        
居住         36  32888.5  913.57
餐饮        984  23583.0   23.97
购物         29   4992.5  172.16
娱乐         46   3178.0   69.09
交通        241   1713.0    7.11
学习         11   1659.0  150.82
医疗          7   1181.5  168.79

排好序以后,把三列放在一起看,就能看出每个类别的「性格」:

  • 餐饮:984 笔,每笔平均 24 元。笔数多、单笔小,钱是一点一点花出去的。
  • 交通:241 笔,平均每笔才 7 元,大多是坐地铁,一年合计还不到 2000 元。
  • 学习、医疗:一年加起来才十来笔,每笔却要一百多元。也就是说,次数少,单笔大。

那么,想省钱的话,该从哪儿下手呢?单笔小、次数多的餐饮,每顿省一点,就能积少成多;单笔大的购物,少买一两件,效果立竿见影。

到这里,分组都是按类别来分的。可要是想知道每个月花了多少呢?下一节就来按月分组。在那之前,先做一道练习:换成按付款方式分组,看看每种付款方式平均一笔多少钱。

练习 1 / 3每种付款方式,平均一笔多少题目有问题?

读进记账本,按付款方式(payment)分组,算出每种付款方式平均一笔多少钱,保留两位小数,从大到小排序后打印。

运行后的输出应该是:

文本
payment
银行卡    186.18
支付宝     33.00
微信       26.54
现金       23.88
Name: cost, dtype: float64
main.py
可编辑
做对当前题解锁下一段 ·03

推荐一个,全网最全最友好的中文 AI 编程指南: coding.stormzhang.ai

学习目录