使用 Matplotlib 与 Seaborn 可视化数据分布:以明尼苏达州鸟类数据集为例
2026/9/11 8:30:18 网站建设 项目流程

使用 Matplotlib 与 Seaborn 可视化数据分布:以明尼苏达州鸟类数据集为例

【免费下载链接】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 课程第 10 课(3-Data-Visualization/10-visualization-distributions),围绕数据科学中极其核心的问题——"数据是如何沿某一坐标轴分布的"——展开。我们将基于课程仓库自带的明尼苏达州鸟类数据集(data/birds.csv),系统学习如何使用 Pandas + Matplotlib 构建直方图(histogram)、2D 直方图,以及如何使用 Seaborn 构建平滑的核密度估计图(KDE density plot),最终掌握从"散点图粗看"到"直方图定量分析"再到"密度图精细刻画"的完整分布可视化方法论。学完本文,你将能够独立处理数值型与文本型两类特征,并通过调节binsbw_adjusthue等关键参数挖掘数据背后的分布规律。

本文所有代码示例均可在课程的 notebook.ipynb 中复现,完整的可运行版本见 solution/notebook.ipynb。

数据集概览:导入 Pandas、Matplotlib 与鸟类数据

在上一课(第 9 课,可视化数量)中,我们已经通过可视化离群值发现了一些错误数据,并依据"最大体长"考察了不同鸟类类别之间的差异。本节课我们换一个分析视角:不去比较单一数值的大小,而是观察整个数据集的分布形态——例如明尼苏达州鸟类最大翼展(MaxWingspan)或最大体重(MaxBodyMass)的整体分布情况。

首先在 notebook.ipynb 中导入 Pandas、Matplotlib 并读取数据:

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

提示:相对路径../../data/birds.csv是相对于 notebook 所在目录(3-Data-Visualization/10-visualization-distributions/)的写法;在仓库根目录中,该文件即 data/birds.csv。数据集共包含 400 余条鸟类记录,除名称、学名、分类学层级等文本字段外,还提供了MinLengthMaxLengthMinBodyMassMaxBodyMassMinWingspanMaxWingspan等数值字段以及ConservationStatus(保护状态)分类字段。

前 5 行数据大致如下:

序号名称学名类别保护状态最小区长最大区长最小区体重最大区体重最小翼展最大翼展
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

先用散点图获得分布的整体直觉

在深入统计图表之前,一个快速有效的做法是沿用上一课学过的散点图:把每个数据点"摊"在坐标平面上,肉眼即可判断数据沿坐标轴的疏密情况。

birds.plot(kind='scatter', x='MaxLength', y='Order', figsize=(12,8)) plt.title('Max Length per Order') plt.ylabel('Order') plt.xlabel('Max Length') plt.show()

这张图(见课程 images/scatter-wb.png)给出了"体长按鸟类目(Order)如何分布"的整体概览:可以看到大部分"点云"集中在中短体长区域,而少数目拥有明显的长尾。

不过,散点图适合做定性概览,却并不擅长精确表达"分布在每个区间的密度到底是多少"。这正是直方图的用武之地。

用直方图刻画数值分布

Matplotlib 为分布可视化提供了非常成熟的直方图工具。直方图在外观上类似条形图,但其含义完全不同:条形图比较的是不同类别的大小,直方图展示的是连续数值按区间(bin)划分后的频数,柱子的高低起伏即为分布形态

创建直方图只需指定图表类型为'hist'。以下代码绘制MaxBodyMass在整个数据集数值范围内的分布,并通过bins参数将数据划分成 10 个小区间:

birds['MaxBodyMass'].plot(kind = 'hist', bins = 10, figsize = (12,12)) plt.show()

可以看到,数据集中的绝大部分鸟类最大体重集中在 2000 以下,呈现出明显的右偏(正偏)形态——这符合生态学的直觉:小型鸟类数量多,超大体型的鸟类稀少。

调节 bins 参数获取更精细的信息

直方图的分辨率完全取决于bins。将分箱数量从 10 提升到 30:

birds['MaxBodyMass'].plot(kind = 'hist', bins = 30, figsize = (12,12)) plt.show()

bins越大,柱子越窄、越能反映局部的细节波动;bins越小,曲线越平滑、越容易看清整体趋势。实践中通常需要多次尝试,找到一个既能保留结构又不引入噪声的分箱数。

过滤数据以放大关注的分布区间

上面的直方图整体右偏严重,左侧"高峰"被压缩得很扁。若想观察体长较小的鸟类群体的分布细节,可以先对 DataFrame 做布尔过滤,再对子集绘制直方图。课程示例中按MaxBodyMass过滤出体重小于 60 的记录并设置bins = 40

filteredBirds = birds[(birds['MaxBodyMass'] > 1) & (birds['MaxBodyMass'] < 60)] filteredBirds['MaxBodyMass'].plot(kind = 'hist', bins = 40, figsize = (12,12)) plt.show()

过滤后的直方图(见 images/dist3-wb.png)明显不再严重左偏,柱状形态更加均匀,能够更清楚地看出小体重区间内部的次高峰结构。

✅ 动手练习:尝试其他过滤条件与数据点组合;如果想观察数据全貌,可以去掉['MaxBodyMass']的列索引,直接对 DataFrame 的数值列绘制带图例标签的分布图。

2D 直方图:同时观察两个分布的联合关系

直方图还能进一步扩展为 2D 形式,用于考察两个分布之间的相关关系。例如同时观察MaxBodyMassMaxLength,Matplotlib 提供了内置的hist2d方法,用颜色亮度表示某个二维区间的聚集程度:

x = filteredBirds['MaxBodyMass'] y = filteredBirds['MaxLength'] fig, ax = plt.subplots(tight_layout=True) hist = ax.hist2d(x, y)

从输出图(见 images/2D-wb.png)可以观察到这两个量沿着预期的轴线存在清晰的线性相关趋势,且在某一点附近存在一个格外明亮的聚集点——那通常对应数据集中的一个主要类群。

文本数据的分布:按保护状态叠加直方图

到目前为止我们处理的都是数值列。但本数据集还包含非常有价值的分类信息:类别(Category)、属(Genus)、种、科(Family)以及保护状态(ConservationStatus)。例如,我们想知道:鸟类按保护状态划分,其分布是怎样的?

数据集中的保护状态采用 IUCN 红色名录(IUCN Red List Categories)的缩写:

  • CR:极危(Critically Endangered)
  • EN:濒危(Endangered)
  • EX:灭绝(Extinct)
  • LC:无危(Least Concern)
  • NT:近危(Near Threatened)
  • VU:易危(Vulnerable)

由于这些是文本值,不能直接喂给直方图,需要先用loc按状态分别取出对应的数值列(这里取MinWingspan),再逐一绘制叠加的直方图:

x1 = filteredBirds.loc[filteredBirds.ConservationStatus=='EX', 'MinWingspan'] x2 = filteredBirds.loc[filteredBirds.ConservationStatus=='CR', 'MinWingspan'] x3 = filteredBirds.loc[filteredBirds.ConservationStatus=='EN', 'MinWingspan'] x4 = filteredBirds.loc[filteredBirds.ConservationStatus=='NT', 'MinWingspan'] x5 = filteredBirds.loc[filteredBirds.ConservationStatus=='VU', 'MinWingspan'] x6 = filteredBirds.loc[filteredBirds.ConservationStatus=='LC', 'MinWingspan'] kwargs = dict(alpha=0.5, bins=20) plt.hist(x1, **kwargs, color='red', label='Extinct') plt.hist(x2, **kwargs, color='orange', label='Critically Endangered') plt.hist(x3, **kwargs, color='yellow', label='Endangered') plt.hist(x4, **kwargs, color='green', label='Near Threatened') plt.hist(x5, **kwargs, color='blue', label='Vulnerable') plt.hist(x6, **kwargs, color='gray', label='Least Concern') plt.gca().set(title='Conservation Status', ylabel='Min Wingspan') plt.legend();

这里的关键参数值得说明:

  • alpha=0.5:设置半透明填充,使多个直方图叠加时互相可见;
  • bins=20:统一的区间数,保证各组数据按相同刻度对齐;
  • color/label:分别为每个状态指定颜色与图例标签,直接调用plt.legend()即可生成图例。

从结果看,最小翼展与保护状态之间并没有呈现出明显的强相关——各状态的分布大致重叠。你可以用同样的方法测试数据集中的其他字段,并尝试不同过滤器,看看是否能找到有意义的关联。

密度图(Density Plot):用 Seaborn 平滑分布曲线

细心的读者可能已经注意到,前面绘制的直方图都是"阶梯状"的,边缘并不平滑。如果想得到一条平滑的分布曲线,就需要引入密度图(density plot),它基于核密度估计(Kernel Density Estimation, KDE)技术,将每个样本点"摊"成一个核函数后叠加,从而得到连续的密度曲线。

Seaborn 是本节引入的新可视化库,其kdeplot方法即可完成这一工作。先加载 Seaborn,绘制MinWingspan的基础密度图:

import seaborn as sns import matplotlib.pyplot as plt sns.kdeplot(filteredBirds['MinWingspan']) plt.show()

输出(见 images/density1.png)与之前的最小翼展直方图形态一致,但曲线平滑得多。正如 Seaborn 官方文档所言:与直方图相比,KDE 产生的图形更简洁、更易解释,尤其在同时绘制多个分布时优势明显;但如果底层分布有界或不光滑,KDE 也可能引入失真。与直方图一样,表示质量同样取决于平滑参数的选择。换言之,离群值依然会让你的图表"行为怪异"。

用 kdeplot 平滑"锯齿状"的直方图

回到之前用bins=30绘制的那张锯齿明显的MaxBodyMass直方图,用 KDE 重绘即可得到平滑的曲线:

sns.kdeplot(filteredBirds['MaxBodyMass']) plt.show()

如果觉得默认曲线"过于光滑",想保留一些细节,可以调整bw_adjust参数(带宽调整系数)。值越小,带宽越窄,曲线越贴合原始数据、越"毛糙":

sns.kdeplot(filteredBirds['MaxBodyMass'], bw_adjust=.2) plt.show()

对比可见 images/density2.png(默认带宽,平滑)与 images/density3.png(bw_adjust=.2,更少平滑、保留了更多局部起伏)。

✅ 建议:查阅kdeplot的可用参数并自行实验bw_adjustcutclipgridsize等对曲线形态的影响。

用 hue 分组:一目了然地比较多个类别的密度

密度图最强大的场景是在单张图中叠加多个分组。例如,仅用几行代码就可以展示"最大体重按鸟类目(Order)的密度分布":

sns.kdeplot( data=filteredBirds, x="MaxBodyMass", hue="Order", fill=True, common_norm=False, palette="crest", alpha=.5, linewidth=0, )

各参数含义:

  • data/x:指定 DataFrame 与数值列;
  • hue="Order":按"目"对曲线着色并分组;
  • fill=True:对曲线下方区域进行填充;
  • common_norm=False:各组独立归一化,保证每一组的曲线面积都归一为 1,从而公平比较各组内部的形状(而不是受样本量影响);
  • palette="crest":选择 Seaborn 内置的渐变色板;
  • alpha=.5:填充透明度;
  • linewidth=0:不绘制描边线。

二维密度图:观察两个变量的联合密度

kdeplot同样支持二维形式,把xy同时传入即可。下面的代码对比鸟的最小体长(MinLength)与最大体长(MaxLength),并按保护状态着色:

sns.kdeplot(data=filteredBirds, x="MinLength", y="MaxLength", hue="ConservationStatus")

输出(见 images/multi.png)呈现出多个同心等高线状的密度云。观察结果值得进一步探究:"易危(Vulnerable)"鸟类的长度分布是否形成了一个有统计意义的独立聚类?这类二维密度图常用于在分类任务之前快速判断不同类别在特征空间中的可分性。

实践挑战与课后作业

🚀 挑战

直方图相比散点图、条形图和折线图是更复杂的一类图表。请自行检索直方图的优秀应用案例,思考并回答三个问题:它们被用在什么场景?它们能论证或揭示什么?在哪些研究领域或行业中最常见?

作业

参照课程 assignment.md 的要求,将本课学到的技能迁移到另一个全新的数据集(例如来自公开数据竞赛平台的数据):

  • 构建一个 notebook,围绕该数据集"讲述一个故事";
  • 讨论时至少使用 5 张直方图来发现数据的事实;
  • 对数据集来源加以注释说明。

评分标准可参考该文件中的 Rubric:优秀的作业应包含完整注释、注明数据来源,并使用不少于 5 张直方图;缺注释或含 bug 则相应降档。

小结与延伸阅读

本节课完成了从 Matplotlib 到 Seaborn 的分布可视化进阶:

  1. 用 Pandas 读取 data/birds.csv 并快速预览;
  2. 用散点图获得分布的整体直觉;
  3. bins可调的直方图刻画数值分布的形态,并通过布尔过滤聚焦感兴趣区间;
  4. hist2d观察两个数值分布的联合聚集;
  5. 用分组plt.hist处理文本类别(保护状态)的分布对比;
  6. 用 Seabornkdeplot获得平滑密度曲线,掌握bw_adjusthuefillcommon_norm等核心参数,并延伸至二维密度图。

若想深入学习,建议:

  • 阅读 solution/notebook.ipynb,对照本课全部图表的完整可运行代码;
  • 查阅 Seaborn 中kdeplot的文档,理解"一维或多维的连续概率密度曲线"的实现细节;
  • 结合本系列课程的其余章节(如第 11 课比例可视化、第 12 课关系可视化),建立完整的可视化工具箱。

记住本文反复强调的要点:直方图的bins决定分辨率,KDE 的bw_adjust决定平滑程度,而离群值永远是这两类图表的"隐形敌人"——先清洗、再可视化,是数据科学中颠扑不破的准则。

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

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

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

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

立即咨询