3.2 结合 Pandas 进行数据可视化


文档摘要

3.2 结合 Pandas 进行数据可视化 本节摘要:Pandas 的 DataFrame 和 Series 是结构化数据的标准容器,而 Matplotlib 的绘图函数可以直接吃下它们。于是出现了两条路:一条是调用 DataFrame 自带的 plot 方法,一行代码出图,适合快速探索;另一条是把数据手动提取出来,交给 Matplotlib 的面向对象接口精修,适合出报告。本节把两条路都走一遍,再讲 groupby 分组聚合后怎么画,最后说清一个判断:什么时候图省事,什么时候要精细。 你能学到什么 阅读完本节,你应当能够: 说清 DataFrame 和 Series 为什么能和 Matplotlib 无缝衔接。

3.2 结合 Pandas 进行数据可视化

本节摘要:Pandas 的 DataFrame 和 Series 是结构化数据的标准容器,而 Matplotlib 的绘图函数可以直接吃下它们。于是出现了两条路:一条是调用 DataFrame 自带的 plot 方法,一行代码出图,适合快速探索;另一条是把数据手动提取出来,交给 Matplotlib 的面向对象接口精修,适合出报告。本节把两条路都走一遍,再讲 groupby 分组聚合后怎么画,最后说清一个判断:什么时候图省事,什么时候要精细。

你能学到什么

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

  1. 说清 DataFrame 和 Series 为什么能和 Matplotlib 无缝衔接。
  2. 用 plot 方法的 kind 参数一行切出折线、柱状、箱线、散点、饼图等常用图形。
  3. 在需要精修时退回 Matplotlib API,控制颜色、刻度、边框、颜色条。
  4. 用 groupby 分组聚合后把结果直接画出来。
  5. 判断一条可视化任务该用快捷路径还是精细路径。

一、DataFrame 画图为什么顺

上一节我们用裸的 NumPy 数组画图,数据一多就发现一个问题:数组只有位置,没有名字。你想画"每个商品类别的销量",得自己记着第 0 列是类别、第 1 列是销量,一旦列顺序变了,代码就悄悄画错。这时候 Pandas 的价值就出来了——它给数据加上行标签和列名,让"取哪一列、按哪一列分组"都变成显式的、可读的操作。

Matplotlib 对 Pandas 的支持,本质上是"能读懂它的数据"。Series 是一维带索引的数组,DataFrame 是二维带列名的表格。把它们传给绘图函数时,索引和列名会自动落到图上的轴标签和图例上。你不再需要手动去算"x 轴写什么",因为数据自己带着说明。

举个最直观的例子:

import pandas as pd import matplotlib.pyplot as plt s = pd.Series([10, 15, 22, 18, 25], index=['A', 'B', 'C', 'D', 'E']) s.plot() plt.show()

s.plot() 这一行,横轴自动用了索引 A 到 E,纵轴用了数值。这就是"数据自带说明"带来的省事。换成裸数组,你还得另外准备一份 x 轴的标签,这里全省了。

Series 和 DataFrame 可以理解成"带标签的数组"和"带列名的表格"。Series 只有一个索引加一列值,画出来通常是折线、直方、饼图这类单变量图;DataFrame 有行有列,画出来可以是多列折线、分组柱状、箱线这类多变量图。Matplotlib 收到它们时,会自动读索引当横轴、读列名当图例,这也是为什么 Pandas 画图经常连 x、y 都不用显式指定。

数据从哪来这件事,Pandas 也一并解决了。它能把 CSV、数据库查询结果、字典、列表统统收进 DataFrame,你在真实项目里最常见的动作就是"读进一张表,处理,再画"。这一整套衔接,就是 Pandas 在数据分析里地位这么稳的原因:它一头接数据源,一头接 Matplotlib,把中间那段"整理数据"的脏活全包了。

不过要分清楚:Pandas 自己的 plot 方法,和 Matplotlib 的绘图函数,是两套东西。Pandas 的 plot 只是对 Matplotlib 做了一层封装,底层还是调 Matplotlib 去画。理解了这一点,后面两条路怎么选、怎么混用,心里就有数了。

二、plot 方法:一行出图

DataFrame 和 Series 都内置了 plot 方法,靠一个 kind 参数就能切图类型。kind 默认是 line,改成 bar、barh、hist、box、scatter、pie、kde,就换成了柱状、水平柱状、直方、箱线、散点、饼图、核密度图。快速探索时,这一招能让你连换七八种图而不用重写数据准备。

df = pd.DataFrame({'类别': ['A', 'B', 'C', 'D'], '数量': [30, 45, 25, 35]}) df.plot(x='类别', y='数量', kind='bar') plt.show()

这里 x 和 y 直接用列名指定,不用去数"第几列是类别",列名拼错了还会直接报错提醒你。

除了 kind,plot 方法还认一堆常用参数:x 和 y 指定列,figsize 定尺寸,title 定标题,color 定颜色,grid 开关网格,legend 开关图例。这些参数和 Matplotlib 里同名参数是一个意思,会一套就会两套。直方图用 kind='hist' 时还能传 bins 控制柱子数量、edgecolor 描边,和 Matplotlib 的 hist 一模一样。

箱线图是探索阶段最常用的一种,一行就能把多列数据的分布摆在一起比:

box = pd.DataFrame({'甲': np.random.randn(100), '乙': np.random.randn(100) + 1, '丙': np.random.randn(80) - 1}) box.plot(kind='box') plt.show()

这里三列长度不一样也没关系,Pandas 会各自对齐,画成三个并排的箱体。这种"直接把整张表画出来"的爽快,是 plot 方法最大的价值。

饼图也值得一提,但要多留个心眼。Series 直接调 plot(kind='pie') 就能出,饼图适合"几类占比"这种加起来是 100% 的场景;类别一多,扇区挤在一起,人眼根本分不清谁大谁小,这时候换成柱状图反而更清楚。这一点 3.4 节还会专门展开,这里先记住:饼图是占比图,不是万能的分类比较图。

💡 探索阶段的心法就是"快"。先用 plot 方法把数据能画的图都试一圈,看哪个角度能暴露出问题,再决定往哪深挖。这时候纠结颜色、字体是浪费时间。

三、精细控制:退回 Matplotlib API

plot 方法省事,但它的定制能力是"够用"级别,不是"随心所欲"级别。当你要控制每一个刻度的位置、去掉某条边框、给散点加颜色条、精确指定图例位置时,plot 方法就捉襟见肘了。这时候把数据手动取出来,交给 Matplotlib 的面向对象接口。

退回的第一步是创建 Figure 和 Axes,然后对 Axes 一步步精修:

fig, ax = plt.subplots(figsize=(8, 6)) ax.bar(df['类别'], df['数量'], color=['#4e79a7', '#f28e2b', '#59a14f', '#e15759']) ax.set_title('各类别销量', fontsize=16) ax.set_ylabel('销量', fontsize=12) ax.spines['top'].set_visible(False) ax.spines['right'].set_visible(False) for i, v in enumerate(df['数量']): ax.text(i, v + 1, str(v), ha='center', va='bottom') plt.tight_layout() plt.show()

这段代码做的事,plot 方法很多做不了:给每个柱子指定不同颜色、去掉上边框和右边框、在柱子顶部加数值标签。ax.spines 这套控制边框的写法,是 Matplotlib 面向对象接口的招牌,也是"精修"和"凑合"的分水岭。

散点图也能精修得更专业,比如按第三列给点着色,再加颜色条:

scatter = pd.DataFrame({'x': np.random.rand(50), 'y': np.random.rand(50), 'z': np.random.rand(50)}) fig, ax = plt.subplots(figsize=(7, 7)) pts = ax.scatter(scatter['x'], scatter['y'], c=scatter['z'], cmap='viridis', s=80, alpha=0.7) fig.colorbar(pts, ax=ax) ax.set_aspect('equal') plt.show()

c 参数按 z 列着色,cmap 指定色板,fig.colorbar 挂上颜色条。这种"三个变量画进一张二维图"的能力,是 plot 方法给不了的。

精修这件事,说到底是在跟 Axes 上的一个个"元素"打交道。spines 是图四周那四根边框线,去不掉的话图会显得拥挤;text 是任意位置的文字,用来给柱子或关键点加注;colorbar 是颜色和数值的对照条。plot 方法把这些都藏起来了,只留几个常用参数,而 Matplotlib API 把它们摊开给你。什么时候该退回来?一个简单的判断是:当你说"要是能把这个、那个改一下就好了",而 plot 方法的参数表里找不到对应的项,就是该退回的时候了。

退回时还有两个容易被忽略的细节。一是数据类型:如果某列看着是数字、其实是字符串,画出来会乱,退回 API 后可以顺手把列转成数值类型。二是索引顺序:折线图是按索引顺序连线的,如果索引是乱的,线会绕来绕去,画之前先按索引排个序,趋势才顺。这些小坑都属于"数据对了,图才对"的范畴,和上一节讲的数据清洗是一脉相承的。

四、分组聚合再画

数据分析里最常见的动作,不是画原始数据,而是先分组算个数,再画结果。Pandas 的 groupby 就是干这个的,而且它算完的结果依然是个 Series 或 DataFrame,可以直接继续画——处理和分析在这条链上无缝衔接。

sales = pd.DataFrame({ '类别': ['A', 'B', 'A', 'B', 'A', 'B'], '地区': ['东', '东', '西', '西', '东', '西'], '金额': [150, 200, 180, 220, 250, 190], }) by_cat = sales.groupby('类别')['金额'].sum() by_cat.plot(kind='bar') plt.show()

groupby('类别') 按类别分组,['金额'].sum() 对每组金额求和,得到一个 Series,再 plot 画成柱状图。整条链读下来就是一句话:"按类别分组,求金额总和,画柱状图"。

更复杂一点的分组,用 unstack 把分组结果摊平成表格,就能画堆叠柱状图:

pivot = sales.groupby(['地区', '类别'])['金额'].sum().unstack() pivot.plot(kind='bar', stacked=True) plt.show()

groupby 传两个字段,unstack 把"类别"从行索引抬到列上,得到一张"地区为行、类别为列"的表,stacked 参数再把它画成堆叠柱状图。这种"分组、摊平、堆叠"的三连,是 Pandas 可视化里最值钱的动作组合。

时间序列是分组聚合的另一大战场。Pandas 对日期索引的支持很完整:把日期列转成 datetime 类型再设为索引,就能按天、周、月做重采样,算移动平均,然后把平滑后的趋势画成折线。比如把每天的流水按月汇总、再画月度走势,就是 resample 加 plot 两行的事。这类"先降噪再看趋势"的操作,是分析师做时间序列探索时的标准动作,也是 Matplotlib 折线图最常见的输入来源之一。

如果觉得 groupby 加 unstack 这套绕,Pandas 还提供了一个更直白的数据透视表工具,把"行、列、值"三样直接摆出来,得到一张现成的宽表,再交给 plot 画热力图或堆叠图都行。两种写法殊途同归,groupby 偏过程式、一行行往下读,透视表偏结果式、一眼看出最后长什么样。习惯哪种用哪种,能得出同一张可画图的表就够了。

⚠️ 分组后的结果别忘了它还是 DataFrame 或 Series,别急着转成列表再画——多此一举。直接对分组结果调 plot,索引和列名会自动变成图上的轴和图例,转成列表反而把这些信息丢了。

五、两条路怎么选

Pandas 和 Matplotlib 的配合,本质上就两条路,一张表对比清楚:

维度 plot 方法快捷路径 Matplotlib API 精细路径
上手成本 低,一行出图 高,要理解 Figure 与 Axes
定制深度 浅,常用参数够用 深,元素级控制
适用场景 快速探索、初步 EDA 报告级精修、发布用图
底层关系 封装了 pyplot 直接操作对象
典型动作 换 kind 切图 控 spines、colorbar、text

两条路不是二选一,而是先快后精。探索阶段用 plot 方法铺开,锁定方向后,把那张要拿出去讲清楚的图,退回 Matplotlib API 精修。我们团队的默认流程就是这样:先散着画,再挑一张重点打磨。

落到一个具体任务上,这条链通常是这样的:先用 Pandas 把数据读进来,过滤掉无关行、处理缺失值;再 groupby 分个组、算个统计量;然后 plot 方法快速出几版图看看方向;最后挑出最有信息量的那张,退回 Matplotlib API 改颜色、加标注、调边框,做成能放进报告的样子。整个过程里,数据一直是 DataFrame 或 Series,没有来回转换的断层,这是 Pandas 加 Matplotlib 最舒服的地方。

还有个小技巧:plot 方法其实接受一个 ax 参数,你可以先建好 Axes,再把 Pandas 的图塞进指定的子图里。这样多子图布局时,既能享受 plot 方法的省事,又能掌控画布结构,两条路的边界在这里就模糊了——会混用,才算真正用顺。

说到底,Pandas 和 Matplotlib 不是谁取代谁,而是一个管"数据长什么样",一个管"图画成什么样"。把分界记住:数据进了 DataFrame,就交给 Pandas 收拾;一旦要动图上的元素,就退回 Matplotlib。这条分界线清楚了,两个库怎么配合都不会乱。练熟之后,你会发现自己大部分时间都在 Pandas 里,只在最后几步才碰 Matplotlib。

图:Pandas 与 Matplotlib 协作

图:Pandas 与 Matplotlib 协作

本节速览

  • Pandas 给数据加名字:索引和列名会自动落到图上的轴和图例,省去手动标注。
  • plot 方法是封装:底层还是 Matplotlib,理解这一点才能自由切换两条路。
  • kind 参数是开关:line、bar、hist、box、scatter、pie 一行切换,探索阶段靠它提速。
  • 精修靠 Axes:控 spines、加 colorbar、加 text,这些元素级控制要退回面向对象接口。
  • 分组聚合无缝画:groupby 的结果还是 DataFrame 或 Series,直接调 plot 即可。
  • 先快后精:探索用快捷路径铺开,发布前挑重点图精修,别一上来就精修。

下一节我们往"图形"本身再走深一步,看看箱线图、小提琴图、热力图这些高级统计图形各自回答什么问题。


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