鸢尾花数据集可视化全解析:从直方图到PCA与t-SNE

发布时间:2026/10/21 7:03:39
鸢尾花数据集可视化全解析:从直方图到PCA与t-SNE
做数据分析这几年鸢尾花数据集始终是我向新人推荐的第一份练手材料。别小看这个只有150条样本、4个特征的小数据集它几乎是所有可视化分析技巧的浓缩训练场。从单变量分布到多变量联动从特征相关性到分类边界探索在这个集子上你能把主流图表类型全部过一遍而且因为数据量小、维度适中画出来的图清晰直观特别适合建立“图表→结论”的映射感。这篇博客我想把一套比较全面的鸢尾花可视化分析方案拆开讲清楚包括每一类图能回答什么问题、参数怎么调、代码怎么落地以及我自己踩过的几个坑希望能给正在学数据分析或者准备做特征探索的朋友一点参考。先说清楚这篇能给你什么。如果你刚接触数据可视化看完可以照着代码一步步跑通理解每种图表背后的分析意图如果你已经有基础可以直接跳到第3章的代码部分里面有不少细节配置是我反复试出来的。整体思路是从单变量开始、再到双变量、最后用投影方法看全局结构这也是我处理任何表格型数据时习惯走的分析路径。1. 整体设计思路为什么选鸢尾花以及“全面”到底指什么1.1 数据集的先天优势与信息盘点鸢尾花数据集Iris Dataset由英国统计学家在20世纪30年代整理收集了3个鸢尾花品种各自50条样本每条样本记录4个数值型特征花萼长度sepal length、花萼宽度sepal width、花瓣长度petal length、花瓣宽度petal width。标签是品种名山鸢尾setosa、变色鸢尾versicolor、维吉尼亚鸢尾virginica。这个数据集之所以成为经典有几个很关键的原因。首先特征数量适中4个数值特征加上1个标签刚好能在二维平面上做比较直观的分析又不至于像MNIST那样一上来就是784维让人摸不着头脑。其次类别是天然平衡的每个品种50条样本不存在类别不平衡的问题画出来的图不会因为样本量差异产生误导。第三这里面存在明显的可分性差异山鸢尾的花瓣特征与其他两类差异很大而变色鸢尾和维吉尼亚鸢尾在部分特征上有重叠这就给分类边界分析留下了讨论空间。我在真正动手画图前习惯先对数据集做一次“体检”也就是看基础统计信息、缺失值情况、数据类型分布。很多人急着绘图结果数据里有缺失值或者类型没转对画出来的图要么报错要么完全失真。对鸢尾花数据集来说它本身是干净的但“检查数据质量”这个步骤不能跳这是数据分析的习惯问题。1.2 全面可视化的四层分析框架“较全面”三个字不是口号它需要有具体的分析维度来支撑。我通常把可视化的层次拆成四层鸢尾花数据集正好每一层都能覆盖到。第一层是单变量分析Univariate Analysis核心回答“每个特征自己长什么样”。直方图、核密度估计图、箱线图都属于这一层。第二层是双变量分析Bivariate Analysis核心回答“两个特征之间是否有关系、关系是怎样的”。散点图是这一层的主角配合颜色映射后还能同时看清类别分布。第三层是相关性分析用热力图把特征两两之间的线性相关程度量化出来。这一层不仅仅是看图还要能从数值上判断哪些特征组合对分类最有帮助。第四层是降维与全局结构分析PCA和t-SNE这类投影方法可以把多维数据压到二维平面让我们一眼看出整体的分布结构和类别聚集情况。这四个层次加起来才算得上“全面”。只画几个散点图那叫入门练习不叫全面分析。1.3 工具选型matplotlib seaborn sklearn 的搭配逻辑我见过很多人纠结于“到底用Pandas自带的绘图方法还是用matplotlib手写”其实没有必要。我的做法是基础绘图用matplotlib统计图表用seaborn数据加载和降维用scikit-learn数据分析用Pandas。这套组合拳在数据科学领域基本是标配你换到任何一台装了Python的机器上都能迅速搭起来。选seaborn而不是完全用matplotlib原因在于seaborn是构建在matplotlib之上的高层统计绘图库它对分布图、箱线图、热力图、成对图这类统计图表做了非常人性化的封装。比如boxplot默认就会给出四分位数范围的样式heatmap直接就能配注解和颜色条省掉了很多底层参数调试。而matplotlib的灵活度更高碰到需要精细控制布局、坐标轴刻度、自定义标注的场景时还得回到它上面来。sklearn则负责提供数据集和降维算法load_iris()函数一行代码就能拿到数据PCA和t-SNE的调用也极其简洁。如果你是在Jupyter Notebook里操作记得在开头加上%matplotlib inline这样才能在单元格下方直接看到图片输出。我早期经常忘记这个魔法命令结果画了半天图什么都看不到后来养成习惯凡是新开Notebook第一件事就是把该导入的库和这个命令先写上。2. 各类可视化的原理拆解与读图要点2.1 单变量分布直方图、密度图、箱线图联合使用单变量分布图的关键目的不是把图画出来就完了而是要从形状里读信息。拿花萼长度这个特征举例它的数据范围大概是4.3到7.9厘米山鸢尾的峰值集中在5厘米上下维吉尼亚鸢尾偏向右端接近6到7厘米。直方图的作用就是把这些信息用条形的方式呈现出来但这里有个重要配置组数bins。bins数量直接决定直方图呈现的粒度。组数太少分布的真实形态会被抹平组数太多又会出现大量空档图形像梳子一样支离破碎没法看出整体趋势。我在画鸢尾花特征的时候一般先试bins15或者bins20观察一下形状是否合理再根据情况微调。有读者可能觉得随手设个10就够了但我建议花30秒多试几个值这是培养图表审美的一部分。单纯看直方图其实不容易对比不同类别之间的分布差异这时候我就会把三个品种分开展示或者在同一个坐标系里用透明度叠起来画。叠加方式有个小技巧必须给alpha参数设置0.5到0.7之间的值否则后面的类别被前面的挡住根本看不出重叠部分。我见过很多新手忘了加透明度结果三个直方图叠在一起糊成一团那就是无效可视化。箱线图在单变量分析里的价值在于它能高效呈现分布的关键统计量中位数、四分位距、离群点。通过观察箱体位置和胡须长度能快速判断分布形态和异常值情况。结合小提琴图violin plot来看更好小提琴图相当于把直方图的信息用密度曲线拟合后与箱线图结合能显示出分布内部的密度高低比如可以明显看出山鸢尾的花瓣长度呈现单峰且集中的分布而维吉尼亚鸢尾则呈现出更宽的分布范围。2.2 双变量关系散点图是核心武器双变量可视化的核心回答的是“两个特征之间是否存在趋势、聚集或分离”。最常用的图就是散点图。把x轴设为花萼长度、y轴设为花萼宽度每个样本对应一个点再按品种用不同颜色标注就能直观看到这三个类别的分布范围。山鸢尾的样本大体集中在图的左下区域点与点之间相对紧凑变色鸢尾居中维吉尼亚鸢尾分布在右边和上边一侧。三个群体呈明显的团状分布彼此有些重叠但整体边界还是可以分辨的。如果要把散点图画得像模像样有几个小细节值得注意。第一点尺寸s不要太大我用的是60左右过大的点会相互遮挡第二颜色方案的选择。我习惯用seaborn默认的色调它在浅色背景下对比鲜明但也要考虑后续是否有打印需求如果需要黑白打印最好用不同形状来区分而不仅仅是颜色。第三因为样本量只有150个还要考虑重叠问题。150个点在二维平面上的重叠其实很常见尤其是山鸢尾的数据点非常集中这时候简单的散点图看起来像是一大团墨迹。好在这类问题影响不大因为三个类别的总体分布还是清楚的。除了散点图seaborn的pairplot几乎是分析多维数据时的神兵利器。它对4个特征两两组合生成一个4乘4的网格对角线是单变量分布非对角线是散点图并且自动按类别着色。一条代码就能生成一组全方位的关系图谱速度还快。我第一次用pairplot的时候就感受到一种“一图胜千言”的冲击感它让我在几秒钟内就锁定了一个关键结论花瓣长度和花瓣宽度这两个特征之间的线性关系最明显而且类别分群效果最好。而后来的PCA分析也印证了这个判断第一主成分几乎就是花瓣特征的综合。2.3 相关性分析热力图的核心价值相关性分析本质上是把双变量关系的强度量化成数值。例如花瓣长度与花瓣宽度之间的相关系数在鸢尾花数据集里能达到0.96左右意味着特征近乎呈线性同步变化。而花萼长度与花萼宽度之间的相关系数只有约-0.42呈负相关。这些数值用热力图来呈现非常直观颜色从深到浅映射了相关性强弱。画热力图用到seaborn的heatmap函数。比较关键的两个参数是annotTrue和cmap。annotTrue会在每个格子中显示相关系数的具体数值否则只能靠颜色深浅来判断误差很大。cmap我用的是coolwarm它是对称色带正值显示为暖色负值显示为冷色中心点在0附近比单一色带的辨识度更高。如果不设置vmin-1和vmax1热力图的色标范围会随数据变化而压缩导致两个热力图之间没法公平比较。对于相关性分析这类标准输出固定好数值范围非常关键。在这里我想提醒一个容易误读的点相关性不等于因果关系。看到花瓣长度和花瓣宽度高度相关不能得出“花瓣长度变化导致花瓣宽度变化”的结论只能说两者之间存在同步变化的趋势可能与遗传因素、生长阶段等共同原因有关。初学者在报告里如果写下“因为相关系数为0.96所以花瓣长度决定了花瓣宽度”这是不严谨的。2.4 降维可视化从多维视角看全局当特征数量增多时二维散点图会失效因为4个特征全画在同一个散点图里是不可能的。PCA和t-SNE就是为这类问题准备的降维武器。PCA主成分分析的核心思想是通过线性变换把原始特征投影到方差最大的方向上。在鸢尾花数据集上第一主成分的方差贡献率通常在0.73左右第二主成分在0.23左右两者累计已经能解释约96%的原始信息。画PCA散点图时把第一主成分作为x轴、第二主成分作为y轴可以看到三个类别呈非常明显的分离状态尤其是山鸢尾与另外两类几乎没有重叠。这进一步印证了前面的分析结论类别的差异主要由花瓣尺寸相关的特征主导。t-SNE与PCA的原理差异很大。t-SNE是一种非线性的流形降维方法它更关注保持样本之间的局部邻域关系。在鸢尾花数据集上t-SNE出来的效果通常比PCA更有视觉冲击力三个类别分成三团极其清晰的云团中间几乎不留重叠。但使用t-SNE需要注意两点一是它的结果不稳定不同的随机种子会生成不同布局使用前最好固定random_state二是t-SNE擅于展示局部聚集结构但它不保留全局几何关系不能说图上的欧氏距离远就表示原始空间中差异大。PCA和t-SNE的可视化适合作为分析报告中的“总览图”因为观众一眼就能看到分类结构和数据整体形态对于那些特征特别多、直接两两画图会画几十张的项目来说这是唯一可行的可视化方式。3. 完整实操从环境准备到每一类图的代码与参数细节3.1 环境准备与数据加载我建议先用conda或者pip建一个干净的Python环境Python版本3.9以上都行。需要安装的库包括pandas、numpy、matplotlib、seaborn、scikit-learn。如果你用的是Anaconda发行版这些库基本已经预装。先看一下数据和基本统计信息这是所有分析的起点。代码如下import numpy as np import pandas as pd import matplotlib.pyplot as plt import seaborn as sns %matplotlib inline from sklearn.datasets import load_iris from sklearn.decomposition import PCA from sklearn.manifold import TSNE # 加载数据 iris load_iris() df pd.DataFrame(iris.data, columnsiris.feature_names) df[species] pd.Categorical.from_codes(iris.target, iris.target_names) # 基础信息 print(数据集形状:, df.shape) print(\n前5行:) print(df.head()) print(\n数据统计信息:) print(df.describe()) print(\n类别分布:) print(df[species].value_counts())这一步输出的结果里describe()给出的均值、标准差、最小值、四分位数对后续判断非常有帮助。比如看花萼宽度的最小值只有2.0最大值达到4.4均值3.05标准差0.43就能大致判断这个特征的整体波动不大。当然这只是热身真正的分析从画图开始。3.2 单变量分布绘制的完整代码与解释我先把四个数值特征以直方图的形式一次性展示出来。使用plt.subplots创建2行2列的子图网格每个子图对应一个特征。给每个子图设置标题、坐标轴标签并且在直方图上叠加核密度估计曲线这样既能看条形分布又能看密度变化。fig, axes plt.subplots(2, 2, figsize(12, 10)) features iris.feature_names colors [#4C72B0, #55A868, #C44E52] for i, ax in enumerate(axes.flat): for j, species in enumerate(df[species].unique()): subset df[df[species] species] ax.hist(subset[features[i]], bins15, alpha0.5, colorcolors[j], labelspecies) ax.set_title(f{features[i]} 分布直方图) ax.set_xlabel(features[i]) ax.set_ylabel(频数) ax.legend() plt.tight_layout() plt.show()这段代码的关键就是循环绘制三种颜色、叠加直方图。alpha0.5保证了三个类别重叠时还能勉强看到底层类别如果透明度再低颜色叠加的区域就会糊成灰色。bins15是我试过的比较稳妥的组数设置。如果你看到直方图某些位置出现明显的空隙可能是bins分得过细可以往下降到10左右试试。箱线图和小提琴图我的做法是单独画一个面板把四个特征横向排列按类别分色。这样能看到每个特征的中位数和四分位距。代码片段如下fig, axes plt.subplots(1, 2, figsize(14, 6)) ax axes[0] sns.boxplot(datadf, xspecies, ydf.columns[0], huespecies, axax, paletteSet2) ax.set_title(花萼长度箱线图对比) ax axes[1] sns.violinplot(datadf, xspecies, ydf.columns[2], huespecies, axax, paletteSet2) ax.set_title(花瓣长度小提琴图对比) plt.tight_layout() plt.show()这里有一个seaborn新老版本的差异需要留意。较新的seaborn版本中如果同时设置x和hue指向同一列可能会有警告提示“hue与x完全一致时请考虑不使用hue”这时只需要删掉huespecies参数即可。不同版本API会有细微差别遇到警告先读一下提示再改不要盲目照抄网上老代码。3.3 双变量散点图与成对图实现散点图的画法很多我建议先用一个基础的scatter函数理解参数后再用seaborn的scatterplot。基础版本的代码是这样的fig, ax plt.subplots(figsize(9, 7)) species_list df[species].unique() markers [o, s, ^] for i, species in enumerate(species_list): subset df[df[species] species] ax.scatter(subset[sepal length (cm)], subset[sepal width (cm)], s60, alpha0.7, ccolors[i], markermarkers[i], labelspecies) ax.set_xlabel(花萼长度 (cm)) ax.set_ylabel(花萼宽度 (cm)) ax.set_title(花萼长度 vs 花萼宽度 散点图) ax.legend() plt.show()我给三个类别分别指定了圆形、方形、三角形的标记这样做的好处是即使图表打印成黑白版本依然能靠形状区分类别。如果你只看颜色很多印刷版报告在灰度输出时完全分不清哪一团是变色鸢尾哪一团是维吉尼亚鸢尾。如果想要更全面的双变量分析直接调用pairplotsns.pairplot(df, huespecies, paletteSet2, markers[o, s, ^], diag_kindkde, height2.5) plt.show()这一行代码值得细聊。huespecies让每个子图自动按品种着色markers参数指定三种标记样式diag_kindkde把对角线上的直方图替换成核密度曲线视觉效果更平滑height2.5控制子图尺寸数值太大整个图会铺满屏幕太小则看不清局部趋势。最终呈现的是一张4行4列的大网格图从这张图里可以快速判断花瓣长度和花瓣宽度的对角线密度曲线在山鸢尾处呈现单一高峰在另外两类处呈现宽分布分类潜力很大花萼宽度与花瓣长度之间看起来没有明显的线性模式分类价值相对弱一些。3.4 相关性热力图的完整实现与标注相关性热力图的分析对象是所有数值型特征标签列要排除在外。代码非常简短plt.figure(figsize(8, 6)) corr df.iloc[:, :-1].corr() sns.heatmap(corr, annotTrue, cmapcoolwarm, vmin-1, vmax1, fmt.2f, linewidths0.5) plt.title(Iris 数据集特征相关性热力图) plt.show()df.iloc[:, :-1]取的是前4列数值特征corr()默认计算皮尔逊相关系数。fmt.2f让数值显示为小数点后两位如果默认输出很长的一串小数表格反而看不清。linewidths0.5在每个格子边缘加了一条细线视觉上更整齐。运行这段代码你会看到四个特征之间的相关系数矩阵。仔细看的话花瓣长度和花瓣宽度的相关系数接近0.96花萼长度和花瓣长度也有接近0.87的相关系数而花萼宽度与花瓣宽度的相关性数值较低大约在0.34左右。这些数字给了我们两个信息一是花瓣类特征之间有强正相关二是花萼宽度在判别品种时携带的信息相对独立。多个特征如果高度相关就意味着它们提供的判别信息有大量重叠后续如果做特征选择完全可以考虑只保留其中一个代表特征。3.5 PCA与t-SNE的实现细节对比采用PCA前通常需要标准化数据因为不同特征的量纲和方差差异会影响主成分方向。虽然鸢尾花数据集的特征都在厘米单位且范围相近但保险起见标准化一下没有副作用。代码from sklearn.preprocessing import StandardScaler scaler StandardScaler() X_scaled scaler.fit_transform(df.iloc[:, :-1]) pca PCA(n_components2) X_pca pca.fit_transform(X_scaled) # 解释方差 print(解释方差比:, pca.explained_variance_ratio_) plt.figure(figsize(8, 6)) for species, marker, color in zip(species_list, markers, colors): mask df[species] species plt.scatter(X_pca[mask, 0], X_pca[mask, 1], s60, alpha0.7, markermarker, colorcolor, labelspecies) plt.xlabel(主成分1) plt.ylabel(主成分2) plt.title(PCA 降维结果可视化) plt.legend() plt.show()这段代码运行后你会在控制台看到类似[0.7296, 0.2285]的输出这说明前两个主成分保留了约95.8%的原始信息。散点图中山鸢尾几乎在左边独立成团变色鸢尾在中间偏上维吉尼亚鸢尾在右边偏下边界区域有轻微的重叠但整体区分度已经很高。PCA的另一个优势是可以通过pca.components_查看各特征对主成分的贡献权重你可能会发现第一主成分主要由花瓣长度和花瓣宽度贡献第二主成分主要由花萼长度和花萼宽度贡献。t-SNE的代码也很短但有一个需要斟酌的参数perplexity。这个参数可以理解为“每个点考虑多少个邻居”范围通常在5到50之间。在150个样本的小数据集上我一般设到10到15。数值太小局部噪声太大数值太大算法计算量上升且局部结构会过于平滑。还有一个n_iter参数指的是迭代次数为了可复现结果记得设random_state。完整代码tsne TSNE(n_components2, perplexity10, n_iter3000, random_state42) X_tsne tsne.fit_transform(X_scaled) plt.figure(figsize(8, 6)) for species, marker, color in zip(species_list, markers, colors): mask df[species] species plt.scatter(X_tsne[mask, 0], X_tsne[mask, 1], s60, alpha0.7, markermarker, colorcolor, labelspecies) plt.xlabel(t-SNE 维度1) plt.ylabel(t-SNE 维度2) plt.title(t-SNE 降维结果可视化) plt.legend() plt.show()每次运行t-SNE时结果都会有些变化。即使固定了random_state42不同sklearn版本间的实现细节也可能导致布局略微不同这是正常现象。如果看到某次运行结果中三个类别交错混在一起先不要急着怀疑数据有问题尝试调整perplexity大小或者把迭代次数拉高再观察结果变化。4. 避坑指南与问题排查速查4.1 散点图的点重叠问题如何破解山鸢尾的样本在花萼宽度维度上非常集中很多点几乎完全重叠画出来的图就像一个实心团子看不出点数和局部分布密度。这个问题在小样本数据集里很容易被忽视但放到真实业务数据中几乎必然出现。解决办法有几种一是降低透明度叠加让重叠点颜色更深二是给点加上白色边缘edgecolorwhite在线框的帮助下把重叠点稍微分隔开三是使用抖动jitter方法在数据点上加一点随机噪声把重叠的点稍微“震”开这个在小样本数据上效果明显。我在散点图中用的alpha0.7就是这个思路虽然不能完全消除重叠问题但已经能保证观感。4.2 KDE曲线出现锯齿状波动的处理方式有时候绘制核密度估计图曲线尾部会出现明显的小波浪或者毛刺。这通常是因为样本量偏小以及带宽bw设置不合适。seaborn的kdeplot有bw_method参数默认值是基于样本量自动计算的但在一些情况下自动值会偏小导致曲线过拟合产生锯齿。可以手动指定带宽比如设为0.4或者0.5曲线会变得更平滑代价是可能抹掉一些局部细节。对150个样本的小数据集来说平滑一些更利于观察整体趋势。4.3 颜色方案在不同场景下的适配问题默认的seaborn配色在屏幕上看起来鲜艳好看但如果你把图放进论文或者打印报告很多期刊要求灰度印刷颜色区分就会失效。一个稳妥的策略是同时使用颜色和形状双重映射这在我前面的代码里已经体现。此外还可以考虑使用色盲友好配色方案比如colorblind调色板。数据可视化不只是把图画出来更是要把信息准确传达给所有人颜色可辨识度是一个值得花时间优化的点。4.4 热力图显示不全或色条范围问题有些读者会碰到热力图格子内的数字显示不全或者颜色始终是同一色调看不出差异的现象。第一个问题的原因是figsize设得太小格子面积不足导致数值被截断。把figsize从默认的(6,4)改成(8,6)或者更大就可以了。第二个问题的根源大都是没设置vmin和vmaxseaborn会按照当前数据的最小值和最大值去映射颜色如果当前数据范围只落在0.34到0.96之间那颜色就只剩暖色到红色的一小段区间缺乏对比。把vmin-1、vmax1补上色带就能完整表达从负到正的相关关系。4.5 t-SNE结果漂移问题与参数选择技巧t-SNE的一个特点是每次运行布局都可能不同原因在于它使用了随机初始化和迭代优化。调试时如果发现这次画出来三个类别很清晰下次运行却变乱了先检查random_state是否固定。固定之后如果还是觉得分离效果不理想可以尝试调整perplexity。这个参数我一般按样本量的十分之一左右来设定初始值150个样本就从15附近开始试。learning_rate默认值是200如果训练过程中损失值异常波动也可以适当调大比如500。t-SNE适合探索性分析画出来的图不要过度解读坐标轴距离它的横纵坐标本身没有可解释单位。4.6 分析报告的结构建议与经验心得当四层可视化都跑完最后写总结报告时我建议按“数据概览 → 单变量分布 → 双变量关系与相关性 → 降维总览 → 结论”的结构组织把关键图片嵌入对应章节并配上简短的图表解读。不要把所有的图堆在一页里那会让读者失去重点。每个图都要有“它支持了什么结论”的说明比如直方图与小提琴图说明花瓣特征在三个品种间差异显著可作为分类依据散点图与成对图说明花瓣长度与宽度线性关联较强两特征组合图可分性最好热力图量化了特征相关性指出花瓣类特征信息冗余度高后续建模可考虑精简特征PCA和t-SNE从全局视角验证了三个类别的可区分性并为后续聚类或分类任务提供了先验判断我个人在实际操作中的一个体会是可视化分析最终是为了辅助决策而不是为了生成一堆漂亮的图表。每次画完图都要回到业务问题或者建模目标上问一问这张图是否能帮我们简化判断、发现模式、验证假设。如果一张图画出来除了“好看”之外没有任何分析价值那它就应该从最终报告里移除而不是继续占据版面。最后再分享一个小技巧。如果你手头有别的三维或者高维数据不妨也先按照这套“单变量→双变量→相关性→降维”的顺序走一遍。不要一上来就套用复杂的机器学习模型先让数据自己说话很多时候可视化的过程中就已经能发现关键问题省掉后面大量试错时间。鸢尾花数据集只是起点把这套方法练熟了面对更大的表格型数据时你就能更快地锁定真正值得深挖的特征组合。