Data-Science-For-Beginners 第 09 课实战:用 Matplotlib 对数量(Quantity)做线性图、散点图与柱状图可视化
2026/9/10 16:27:48 网站建设 项目流程

Data-Science-For-Beginners 第 09 课实战:用 Matplotlib 对数量(Quantity)做线性图、散点图与柱状图可视化

【免费下载链接】Data-Science-For-Beginners10 Weeks, 20 Lessons, Data Science for All!项目地址: https://gitcode.com/GitHub_Trending/da/Data-Science-For-Beginners

本篇指南基于 Data-Science-For-Beginners 仓库第 09 课《Visualizing Quantities》(可视化数量)展开,围绕一份明尼苏达州鸟类数据集 birds.csv,完整演示如何用 Python 的 Matplotlib + Pandas 组合完成从“读入数据—画线性图—标注坐标轴—定位并过滤异常值—做分组柱状图—叠加对比”的全过程。读完后,你将能够独立完成数量类数据的三类核心图表(line / scatter / bar)绘制、用tick_paramsplt.textrcParams等 API 精细控制坐标轴与标签,并掌握“从图中发现异常值、再反向清洗数据”的实战工作流。

课程背景:为什么用鸟类数据集练“数量可视化”

本课程的定位是:当你拿到一份数据集,需要搞清楚“某个东西到底有多少”时,第一任务就是检查它的数值分布。仓库为此提供了一份已清洗过的数据集 birds.csv,共 443 条鸟类记录(不含表头),字段混合了文本与数值:

字段类型含义
Name/ScientificName文本鸟类俗名 / 学名
Category/Order/Family/Genus文本分类学层级(类群/目/科/属)
ConservationStatus文本保护状态(如 LC)
MinLength/MaxLength数值体长范围(厘米)
MinBodyMass/MaxBodyMass数值体重范围(克)
MinWingspan/MaxWingspan数值翼展范围(厘米)

Matplotlib 的通用绘图流程可以概括为五步:识别 dataframe 中要用的列 → 对数据做必要变换 → 指定 x/y 轴的取值 → 选择图表类型 → 显示图形。本课聚焦最适合表达“数量”的三种图:线性图(line)、散点图(scatter)、柱状图(bar)。

选图原则(直接决定图表能不能讲清故事):

  • 分析随时间的趋势:线性图
  • 比较数值大小:柱状图、条形图、饼图、散点图
  • 展示部分与整体的关系:饼图
  • 展示数据分布:散点图、柱状图
  • 展示趋势:线性图、条形图
  • 展示变量间的关系:线性图、散点图、气泡图

实操时,请先打开本课目录下的 notebook.ipynb 并新建单元格,所有代码都在这份 notebook 中运行。

读入数据并画出第一张线性图

数据文件位于仓库根目录的data文件夹。注意:原文档 notebook 中写的'../../data/birds.csv'是相对于 lesson 文件夹的路径,从仓库根目录看,数据就在 data/birds.csv;若你把 notebook 复制到仓库根目录运行,请相应调整为data/birds.csv

import pandas as pd import matplotlib.pyplot as plt birds = pd.read_csv('../../data/birds.csv') birds.head()

birds.head()输出的前几行(对应 data/birds.csv 前几行)长这样:

NameScientificNameCategoryOrderFamilyGenusConservationStatusMinLengthMaxLengthMinBodyMassMaxBodyMassMinWingspanMaxWingspan
0Black-bellied whistling-duckDendrocygna autumnalisDucks/Geese/WaterfowlAnseriformesAnatidaeDendrocygnaLC475665210207694
1Fulvous whistling-duckDendrocygna bicolorDucks/Geese/WaterfowlAnseriformesAnatidaeDendrocygnaLC455371210508593
2Snow gooseAnser caerulescensDucks/Geese/WaterfowlAnseriformesAnatidaeAnserLC647920504050135165
3Ross's gooseAnser rossiiDucks/Geese/WaterfowlAnseriformesAnatidaeAnserLC57.36410661567113116
4Greater white-fronted gooseAnser albifronsDucks/Geese/WaterfowlAnseriformesAnatidaeAnserLC648119303310130165

接下来用一条最基础的 Pandas 快捷方法画出最大翼展(MaxWingspan)的线性图:

wingspan = birds['MaxWingspan'] wingspan.plot()

Series.plot()是 Pandas 对 Matplotlib 的薄封装:以序列的索引为 x 轴、数值为 y 轴画折线。第一眼看图就会立刻发现一个严重异常的“尖峰”:某个值接近 2300 厘米——也就是 23 米的翼展,明尼苏达难道有翼龙在飞?这正是本课要演示的核心工作流:不离开图表,直接在工作流内部追查异常值

给 x 轴加标签:先暴露“标签过载”问题

线性图的 x 轴此刻只有索引数字,看不出对应哪种鸟。给坐标轴加上语义化的标题与刻度标签:

plt.title('Max Wingspan in Centimeters') plt.ylabel('Wingspan (CM)') plt.xlabel('Birds') plt.xticks(rotation=45) x = birds['Name'] y = birds['MaxWingspan'] plt.plot(x, y) plt.show()

要点解析:

  • plt.xticks(rotation=45):把 443 个鸟类名称的刻度标签旋转 45 度,缓解横向重叠;
  • plt.plot(x, y)中 x 是类别标签序列(Pandas Series),Matplotlib 会把字符串当作类别轴刻度;
  • 标题、轴名先设置再plt.plot,顺序不影响结果,但必须与plt.show()在同一个当前 figure 上执行。

即便旋转 45 度,443 个标签依然密到不可读。这说明当样本过多时,试图给每个点都打标签是错误策略——正确做法是换一种图型加“选择性标注”。

用散点图 +plt.text只标注异常值

策略调整为:改用散点图腾出标注空间,且只给异常值(翼展 > 500 厘米)打标签

plt.title('Max Wingspan in Centimeters') plt.ylabel('Wingspan (CM)') plt.tick_params(axis='both',which='both',labelbottom=False,bottom=False) for i in range(len(birds)): x = birds['Name'][i] y = birds['MaxWingspan'][i] plt.plot(x, y, 'bo') if birds['MaxWingspan'][i] > 500: plt.text(x, y * (1 - 0.05), birds['Name'][i], fontsize=12) plt.show()

这段代码逐行拆解:

代码作用
plt.tick_params(axis='both', which='both', labelbottom=False, bottom=False)同时作用于 x/y 轴的主次刻度(which='both'),labelbottom=False隐藏底部刻度文字、bottom=False移除底部刻度线,彻底腾出标签空间
plt.plot(x, y, 'bo')'bo'是 Matplotlib 简写格式符:blue + circle,画一个蓝色小圆点,即散点
if birds['MaxWingspan'][i] > 500阈值过滤:绝大多数鸟类翼展在几十到两百多厘米,只有超过 500 才值得标注
plt.text(x, y * (1 - 0.05), ...)在该点上方 5% 处(向下偏移,避免与点重合)写入文字标签
fontsize=12保证标签在密集图中仍可读

图中浮在高空的两个标签就是异常值:Bald eagle(白头海雕)与 Prairie falcon(草原隼)。

过滤异常值:从“看图”回到“改数据”

结合常识判断:一只翼展 25 米的白头海雕几乎不可能存在——真实翼展约 2 米出头。回查数据源 data/birds.csv 可以确认,这两条记录的数值多写了一个0:Bald eagle 的MaxWingspan为 2300(正常应为 230),Prairie falcon 为 1100(正常应为 110)。这是典型的录入错误(typo)型异常值。

本课给出的处理方式是:先不修改原始数据,而是在绘图时用名称白名单把它们排除掉,观察过滤后的数据形态:

plt.title('Max Wingspan in Centimeters') plt.ylabel('Wingspan (CM)') plt.xlabel('Birds') plt.tick_params(axis='both',which='both',labelbottom=False,bottom=False) for i in range(len(birds)): x = birds['Name'][i] y = birds['MaxWingspan'][i] if birds['Name'][i] not in ['Bald eagle', 'Prairie falcon']: plt.plot(x, y, 'bo') plt.show()

过滤掉两个异常点后,整个分布立刻变得紧凑且可理解——这就是“可视化驱动的数据清洗”:图先暴露问题,数据再修正问题。后续练习不依赖翼展数值,你也可以选择:过滤这两条记录、或直接修正 CSV 中的笔误。

从分布走向计数:用柱状图回答“有多少”

线性图与散点图展示的是单个数值的分布;而“数量”问题更常问的是分组计数,例如:

  • 有多少个鸟类类别(Category),各自数量是多少?
  • 有多少种鸟是灭绝、濒危、罕见还是常见的?
  • 按林奈分类学,各属(Genus)、各目(Order)分别有多少?

柱状图正是回答这类问题的工具。

反例:直接对全量数据堆叠

最直接的写法是把整个 dataframe 丢给 Pandas 的绘图接口:

birds.plot(x='Category', kind='bar', stacked=True, title='Birds of Minnesota')

这张图不可读:每个类别下又按 443 条记录堆叠,柱子内部毫无意义地拥挤。这个反例本身就是一课:柱状图不能对着原始明细数据画,必须先做聚合

正例:Pandas 聚合 + Matplotlib 绘图

正确分工是:Pandas 负责管理数据(分组、计数、排序),Matplotlib 只负责画图。统计每个Category出现的次数并按数量排序,再把图拉高以适应类别数量:

category_count = birds.value_counts(birds['Category'].values, sort=True) plt.rcParams['figure.figsize'] = [6, 12] category_count.plot.barh()

参数说明:

  • value_counts(..., sort=True):对类别数组计数并降序排列,结果是一个索引为类别名、值为计数的 Series;
  • plt.rcParams['figure.figsize'] = [6, 12]:把画布从默认约 6.4x4.8 英寸改为 6x12 英寸的竖版,容纳全部类别;
  • plot.barh():横向条形图(bar horizontal),类别名天然适合横向展示长文本标签。

对 data/birds.csv 做分组计数可以验证这一结论:全表共 53 个类别,其中Ducks/Geese/Waterfowl(鸭/雁/水禽)以 45 种居首,其后是New World warblers(41 种)、Sandpipers/Allies(34 种)、Gulls/Terns/Skimmers(28 种)。一眼就能看出该地区鸟类以水禽为主——明尼苏达号称“万湖之州”,完全符合预期。也可以自己换ConservationStatusGenusOrder等列再做计数,看看还有什么意外发现。

组间比较:新建坐标轴与叠加绘制

比较各类别的 MaxLength

换一个维度:比较每个类别的MaxLength(体长上限):

maxlength = birds['MaxLength'] plt.barh(y=birds['Category'], width=maxlength) plt.rcParams['figure.figsize'] = [6, 12] plt.show()

注意这里的写法与前例不同:直接调用 Matplotlib 的plt.barh,用原始明细数据逐条画横条,而不是先聚合。结果:蜂鸟(Hummingbirds)的 MaxLength 最小,鹈鹕、大雁类最大——数据讲出了一个符合常识的故事。

叠加 Min/Max 看区间

更进一步的技巧是在同一坐标轴上叠加两次barh,把同一类别的最小长度和最大长度画在一起,形成区间对比:

minLength = birds['MinLength'] maxLength = birds['MaxLength'] category = birds['Category'] plt.barh(category, maxLength) plt.barh(category, minLength) plt.show()

两次调用共享同一个 figure,后画的短条(MinLength)叠在先画的长条(MaxLength)之上,肉眼看即可读出每个类别的长度区间。从图上可以得出一个稳健结论:鸟越大,体长区间的绝对跨度也越大——大鸟的 Min/Max 差值明显宽于小鸟。

小结与延伸练习

本课的完整技能链是:

  1. pd.read_csv读入混合类型数据,head()检查结构;
  2. Series.plot()快速出图,用“反直觉的尖峰”定位异常值;
  3. plt.xticks(rotation=45)处理刻度旋转,tick_params隐藏刻度、plt.text做选择性标注;
  4. value_counts(sort=True)聚合 +plot.barh()+rcParams['figure.figsize']输出可读的分组计数图;
  5. 用两次plt.barh叠加展示区间,做组间比较。

课后练习(对应 assignment.md):选一个具体物种(例如 Snow goose 雪雁),围绕它建一个 notebook,综合运用线性图、散点图、柱状图三种图型讲一个完整的数据故事。评分标准看三要素:注释是否到位、故事线是否连贯、图表是否美观。

延伸阅读:本仓库后续课程会继续用同一份鸟类数据集展开分布可视化(直方图、密度图)与比例可视化(饼图、华夫图)等主题;Matplotlib 官方提供 PDF 版 cheatsheet 可作日常速查;若需要交互式图表,可自行研究 Plotly 等替代库。

【免费下载链接】Data-Science-For-Beginners10 Weeks, 20 Lessons, Data Science for All!项目地址: https://gitcode.com/GitHub_Trending/da/Data-Science-For-Beginners

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询