Python数据分析实战:用Matplotlib绘制鸢尾花散点图

发布时间:2026/10/21 4:31:28
Python数据分析实战:用Matplotlib绘制鸢尾花散点图 在数据分析这条路上我做过不少练手项目但凡是绕不开的总有几个固定节目——泰坦尼克号、房价预测、鸢尾花。今天这篇就聚焦在鸢尾花Iris数据集上专门用matplotlib把散点图玩明白。项目标题叫“Python数据分析项目实例3”但别被“实例3”劝退它并不是什么高深论文而是一个非常适合新手建立可视化手感、也适合老手快速验证分析思路的经典场景。我会把整个分析过程从头到尾拆开来讲数据加载、清洗检查、特征理解、散点图的绘制与调参以及从图里读出哪些有价值的结论。如果你正好在学Python数据分析或者想把matplotlib的散点图画得更有章法这篇内容可以直接拿来当操作手册。1. 项目目标与拆解思路1.1 为什么选鸢尾花数据集鸢尾花数据集在数据圈的地位差不多相当于编程界的“Hello World”。它由一位统计学家在20世纪30年代整理包含三个鸢尾花品种山鸢尾、变色鸢尾和维吉尼亚鸢尾每个品种各50条样本总共150条记录。每条记录有四个数值型特征——花萼长度、花萼宽度、花瓣长度、花瓣宽度单位都是厘米另外还有一个品种标签。这种数据结构很干净特征不多没有复杂文本也没有大量缺失值。恰恰因为简单它适合用来专注练习“图表怎么画、图里怎么看”而不需要在前处理上消耗太多精力。对于首次接触散点图的人来说这种低干扰环境能更快建立直觉什么样的数据分布会产生什么样的图形颜色和形状映射又是如何帮助人脑做分类的。1.2 散点图在这个项目里要解决什么问题散点图的核心任务是展示两个连续变量之间的关系。放到鸢尾花数据集里就是回答这么几个问题花萼长度和花萼宽度之间有没有相关性花瓣长度和花瓣宽度之间是不是更强的线性关系用任意两个特征的组合能不能把三个品种明显区分开这些问题看起来简单但背后指向的是数据挖掘里一个经典任务特征可分性分析。如果只用某一个特征画出直方图三个品种的分布可能会互相重叠肉眼很难判断。但如果换成二维散点图每个点同时携带两个维度的信息类别之间的差异往往就豁然开朗了。这也是散点图比单变量直方图更强的地方它把“单点孤立看”变成“点群对照看”。1.3 整体流程设计这个项目我按下面几步来走大家可以直接照着这个思路复制到自己的分析场景中加载数据和依赖库确认数据来路和版本。做基础体检数据形状、缺失值、重复值、字段类型。分组统计用数字感受各品种特征的差异。绘制基础散点图先不做任何美化确认坐标轴和点分布是否正常。按品种着色添加图例让类别信息进入画布。用多子图对比不同特征组合寻找区分度最高的搭配。在图上叠加趋势信息量化特征之间的相关程度。整个过程核心就一句话先看数据再画图再从图里反向验证数据规律。2. 环境准备与数据加载2.1 依赖库的安装与检查这个项目用到的库不多核心是matplotlib、pandas和scikit-learn。其中scikit-learn不是必选项但你如果不想手动下载csv文件用它的内置接口加载鸢尾花数据是最省事的。我建议在虚拟环境里操作避免把全局Python环境弄乱。如果你用的是Anaconda或者Miniconda其实环境已经比较完整大概率只缺matplotlib。可以在终端里执行pip install matplotlib pandas scikit-learn安装完以后建议顺手验证一下版本。不同版本的API可能有细微差别尤其是matplotlib有些旧的写法在新版本里已经不被推荐了import matplotlib import pandas as pd import sklearn print(matplotlib:, matplotlib.__version__) print(pandas:, pd.__version__) print(scikit-learn:, sklearn.__version__)我在测试环境里用的是matplotlib 3.8系列画散点图的接口一直很稳定大家如果是3.5以上版本这篇文章里的代码都可以放心跑。2.2 加载鸢尾花数据的三种方式方式一通过scikit-learn的datasets模块加载。from sklearn.datasets import load_iris iris load_iris() print(iris.data.shape) print(iris.feature_names) print(iris.target_names)这种方式的优点是快速数据结构是现成的NumPy数组。缺点也很明显特征名和标签信息放在两个地方第一次接触会觉得别扭。方式二转成pandas的DataFrame。我个人更推荐这种方式因为pandas的DataFrame结构更贴近实际工作中的数据处理习惯打印出来一目了然import pandas as pd df pd.DataFrame(datairis.data, columnsiris.feature_names) df[label] iris.target df[species] df[label].map({ 0: setosa, 1: versicolor, 2: virginica }) print(df.head())加了species这一列中文名之后图例上直接显示品种名比显示数字0、1、2友好得多。方式三直接读csv文件。如果你手头已经有iris.csv文件或者想练一练pandas的read_csv操作也可以这样df pd.read_csv(iris.csv)网上很多教程提供的csv版本列名可能不太一样有些是Sepal.Length这种带点的写法有些是英文全称。读进来之后第一步肯定是看列名然后根据实际情况重命名这里就不再展开。2.3 初步查看数据结构数据加载完成后不要着急画图先看一眼整体情况print(df.info()) print(df.describe())info()告诉你每一列的数据类型和缺失情况describe()则给出了所有数值列的统计描述均值、标准差、最小值、四分位数、最大值。从这些数字里可以先建立一个大体印象比如说花瓣长度的标准差明显比花萼宽度大说明不同品种之间花瓣长度的波动更剧烈那它在分类时可能就更有区分度。用groupby去看每个品种的均值也很直观print(df.groupby(species).mean())看到这个输出之后你心里应该已经有了一点猜测山鸢尾的花瓣明显短而窄其他两种花瓣更长。接下来画散点图其实就是把这些数字印象转化为视觉印象。3. 从数据清洗到基础统计3.1 缺失值与重复值检查可能有人觉得Iris数据集这么经典还需要清洗吗其实在项目里体现“检查”这一步更大的价值在于养成习惯。你的工作环境不总是这么干净如果连面向标准数据集的流程都不完整遇到脏数据时就更措手不及了。print(缺失值情况) print(df.isnull().sum()) print(重复行数, df.duplicated().sum())标准Iris数据集没有缺失值但可能会有重复记录。我用某个版本的csv文件时就曾发现过两三条完全相同的行。虽然这三条重复数据对整体分布影响非常小但严谨的做法是清理掉df df.drop_duplicates().reset_index(dropTrue)重置索引是为了避免删除行之后出现索引空洞后续按索引做图例映射时会出错。3.2 分组统计与特征盘点先按品种分组把核心特征的平均值、标准差拉出来对比print(df.groupby(species).agg([mean, std]).T)转置之后看特征作为行、品种作为列对比会更清楚。我通常关注两点一是同特征在不同品种之间均值差异够不够大二是标准差是否在一个量级。如果某个特征的组间均值差明显大于组内标准差那这个特征对分类就很有利。从分组统计结果能看出来花瓣相关的两个特征在三个品种之间的均值差距非常明显而花萼宽度相对不那么“界限分明”。这不代表花萼宽度没用只是说明单靠它做分类不够需要和其他特征组合。3.3 确定散点图的绘图方案画图之前我把所有特征两两组合的可能性在心里过了一遍。四个特征两两组合有六种情况。如果全部画成散点图六个子图排出来确实全面但信息有冗余读者也容易看花眼。我的方案是先画一张“全局图”花萼长度做横轴、花萼宽度做纵轴按品种着色。再画一张“重点图”花瓣长度做横轴、花瓣宽度做纵轴同样按品种着色。最后再补一个两行两列的四子图把四个特征两两组合中最有代表性的两组放进来对比。这个方案兼顾了“发现规律”和“验证规律”。全局图用来感受整体分布重点图用来确认某个方向上的强可分性。4. 散点图系列实操4.1 第一张散点图花萼长宽 vs 花萼宽度先画最简单的版本只给横轴和纵轴喂数据不指定颜色import matplotlib.pyplot as plt plt.scatter(df[sepal length (cm)], df[sepal width (cm)]) plt.xlabel(Sepal Length (cm)) plt.ylabel(Sepal Width (cm)) plt.title(Sepal Length vs Sepal Width) plt.show()这张图跑出来之后会看到一堆点聚合成几个松散的区域。颜色统一时类别信息全部被隐藏了你只能看出两个变量之间大概呈什么趋势无法判断品种边界。这一步很有必要因为它让你体会到“如果不做颜色映射散点图的信息量是不完整的”。4.2 按品种着色与图例美化接下来是关键一步把species列映射为点的颜色。colors {setosa: #2E86AB, versicolor: #A23B72, virginica: #F73A4C} plt.figure(figsize(8, 6)) for species, color in colors.items(): subset df[df[species] species] plt.scatter( subset[sepal length (cm)], subset[sepal width (cm)], labelspecies, colorcolor, alpha0.7, edgecolorswhite, linewidths0.5 ) plt.xlabel(Sepal Length (cm), fontsize12) plt.ylabel(Sepal Width (cm), fontsize12) plt.title(Iris Sepal Features by Species, fontsize14) plt.legend() plt.grid(True, linestyle--, alpha0.4) plt.show()这里有几个细节值得多说一句。第一alpha0.7让点半透明当数据点大量重叠时透明度可以避免“一堆点糊成一块黑”。第二edgecolorswhite给点加白色描边让点在密集区域仍然保有轮廓视觉上清爽很多。第三图例不是自动就有的必须先给每个scatter调用传入label参数再调用plt.legend()。跑完这张图你应该能比较清楚地看到山鸢尾的样本集中分布在图的左上区域花萼长度偏短但宽度偏宽另外两种鸢尾则总体偏向右侧花萼更长。不过这张图里变色鸢尾和维吉尼亚鸢尾的边界仍然有重叠说明花萼特征组合的区分能力有限。4.3 多子图对比花瓣特征组合再看花瓣长度和花瓣宽度这两个特征这是Iris数据集里公认区分度最高的组合。我把两张图放到一起对比fig, axes plt.subplots(1, 2, figsize(14, 6)) feature_pairs [ (sepal length (cm), sepal width (cm)), (petal length (cm), petal width (cm)) ] titles [Sepal Length vs Width, Petal Length vs Width] for ax, (x_col, y_col), title in zip(axes, feature_pairs, titles): for species, color in colors.items(): subset df[df[species] species] ax.scatter(subset[x_col], subset[y_col], labelspecies, colorcolor, alpha0.7, edgecolorswhite, linewidths0.5) ax.set_xlabel(x_col, fontsize11) ax.set_ylabel(y_col, fontsize11) ax.set_title(title, fontsize13) ax.grid(True, linestyle--, alpha0.4) ax.legend() plt.tight_layout() plt.show()看到右边那张花瓣特征图三个品种的样本几乎分成了三个独立的点群山鸢尾集中在左下角变色鸢尾在中间维吉尼亚鸢尾在右上角。即使中间还有一些黏连整体走势已经非常清晰。这种差异比花萼特征图明显得多基本可以断定花瓣特征是区分品种的“主力特征”。4.4 趋势叠加与分组散点图变体散点图除了点本身还能叠加其他信息。我常用的一种增强方式是加一条线性拟合线配合scipy或者numpy的polyfit完成import numpy as np x df[petal length (cm)] y df[petal width (cm)] coef np.polyfit(x, y, 1) p np.poly1d(coef) plt.figure(figsize(8, 6)) plt.scatter(x, y, cdf[label], cmapviridis, alpha0.7, edgecolorswhite, linewidths0.5) plt.plot(x, p(x), colorred, linestyle--, linewidth2, labelLinear fit: y {:.2f}x {:.2f}.format(coef[0], coef[1])) plt.xlabel(Petal Length (cm)) plt.ylabel(Petal Width (cm)) plt.title(Petal Features with Linear Trend) plt.legend() plt.grid(True, linestyle--, alpha0.3) plt.show()拟合方程的意义在于把“肉眼看到的趋势”转成可表达的量化关系。比如拟合出来斜率接近0.4就说明花瓣宽度每增加1厘米花瓣长度平均会增加约2.5厘米。这种数值信息在后续建模或者汇报里非常有用。还有一种变体是“分组散点图”横轴改成品种类别纵轴是某个特征的取值点向两侧随机抖动以避免重叠类似strip plot。这种图非常适合观察单一特征在不同类别间的分布差异适合配合箱线图一起使用但本期项目主体是散点图这里就不占篇幅了。5. 从图里读出的关键信息5.1 特征可分性解读画图本身不是目的读图才是。散点图给我们的第一层结论是鸢尾花数据集的四个特征虽然都能区分品种但能力有强有弱。从花萼长宽图中可以看到山鸢尾被明显分出来而变色鸢尾和维吉尼亚鸢尾混在一起。这说明这两个特征组合对后两个品种的区分能力不够。从花瓣长宽图中可以看到三种品种的分布呈一条明显的带状从左上到右下并且三个点群依次排开区分度非常高。这种差异背后有生物学解释不同鸢尾品种的花瓣形态差异往往比花萼差异更显著。当然作为数据分析项目我们不需要深入植物学只需要知道“花瓣特征组合的信息量更大”就够了。5.2 图与统计数字的相互印证散点图是感性的统计数字是理性的两者应该互相印证。我通常会计算一下相关系数print(df[[petal length (cm), petal width (cm)]].corr()) print(df[[sepal length (cm), sepal width (cm)]].corr())结果里花瓣长度和花瓣宽度的相关系数通常在0.96左右花萼长度和花萼宽度的相关系数大概在-0.43到-0.12之间甚至可能是负相关。所以在花瓣长宽图里看到的强线性趋势不是错觉是数据本身的高度相关而在花萼长宽图里点比较散也是因为相关性本身就弱。关联到分类问题上高相关不一定意味着好分类但它意味着两个变量在空间中的分布倾向于沿着一条直线铺开。再结合类别标签如果这条直线方向恰好贯穿三个类别区域的中心那线性可分的可能性就很大这正好是花瓣特征的情况。5.3 这类分析思路的扩展场景散点图加类别着色的分析思路绝不只在鸢尾花上有效。我后来在好几类实际项目里都沿用了同样的套路。一个典型场景是电商用户分群。我把用户的“注册时长”和“累计消费金额”分别作为横纵轴按用户所属的活跃等级着色马上就能看出不同等级用户在坐标平面上的分布区域。高价值用户是不是集中在某个区间流失用户是不是散落在特定区域一目了然。另一个场景是设备故障检测。把设备的“运行温度”和“振动频率”画成散点图按是否故障着色如果两类点有明显的空间分离那这两个传感器指标就能作为故障预判的有效特征。所以说Iris这个项目练的不是“鸢尾花本身”而是“多类别样本在二维特征空间里如何展示和解读”的能力。这套能力迁移到任何带数值特征和类别标签的数据集上都成立。6. 常见问题与排查技巧实录6.1 常见报错与解决思路我把这段实操中比较容易踩到的坑整理成了一张速查表方便大家对照排查问题现象常见原因解决方法中文标签显示为方块matplotlib默认字体不含中文字符使用plt.rcParams[font.sans-serif] [SimHei]或改用英文标签图例中显示的是数字而不是品种名没有将标签转换为字符串映射增加species列或在label参数里传入字符串散点图点太多看不清未设置透明度或点过大设置alpha0.6调小s参数保存图片时出现空白边框未使用bbox_inchestightplt.savefig(iris.png, dpi150, bbox_inchestight)颜色条和图例同时出现但颜色不一致cmap映射与label分类混用统一使用循环绘制或统一cmap方案坐标轴标签被截断子图之间空间不足调用plt.tight_layout()这些报错和修复方式都不是什么高深技术但实际写代码时十次有八次栽在这种地方。建议把这张表留在手边下次跑其他散点图项目也能直接用。6.2 我踩过的几个坑第一个坑是直接在plt.scatter()里传字符串列给c参数。早期写代码时图省事plt.scatter(df[x], df[y], cdf[species])结果matplotlib直接报错说无法把字符串转换为浮点数。正确做法就是提前把品种映射成数字或者分品种循环绘制这里也体现了数据预处理阶段创建数值标签列的价值。第二个坑是透明度设太低。有一回画一组重叠度非常高的点我把alpha设成0.2结果整个图看起来灰蒙蒙一片边缘点几乎透明到看不见。后来调整到0.6到0.75之间才找到合适的平衡点。透明度的取值没有标准答案要结合点的数量和重叠程度来判断。第三个坑是图例位置。默认情况下matplotlib会把图例放在右上方如果那个区域恰好有大量数据点图例就会盖住点导致局部信息丢失。我当时试过plt.legend(locbest)但有时自动选择的位置仍然不理想。后来更习惯手动指定位置比如locupper left、loclower right根据实际分布情况现场调整。第四个坑偏分析层面只画散点图不做量化验证。有段时间我看图觉得某个特征组合可分性很好结果一算相关系数和线性判别精度发现并没有想象中那么高。图能提供直觉但直觉需要统计指标去校准。画完图最好顺手算一下相关系数或者用简单的分类模型验证直觉这也是把散点图从“好看”升级为“有用”的关键一步。最后再分享一个提升效率的小技巧把绘图过程封装成一个函数传入横轴列名、纵轴列名、数据框自动生成着色的散点图。这样六组特征组合只需要六次函数调用改图非常轻快。封装函数不只是为了省几行代码更重要的是当你反复迭代特征组合时能保证每次画出来都使用相同的视觉规范出来的图才有一致性。def plot_scatter_by_species(df, x_col, y_col, colors, axNone): if ax is None: fig, ax plt.subplots(figsize(8, 6)) for species, color in colors.items(): subset df[df[species] species] ax.scatter( subset[x_col], subset[y_col], labelspecies, colorcolor, alpha0.7, edgecolorswhite, linewidths0.5 ) ax.set_xlabel(x_col) ax.set_ylabel(y_col) ax.grid(True, linestyle--, alpha0.4) ax.legend() return ax这个函数我后来直接搬到了其他项目里只要把species换成任意类别列几乎不用改代码。从这个角度看鸢尾花散点图项目带给我的其实是一套可以反复复用的绘图模板和一套完整的“看图、读图、验证图”的工作方法。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询