Python数据可视化实战:利用Scikit-learn与Seaborn绘制散点图以区分类别

在这篇文章中,我们将深入探讨如何利用 Python 生态系统中最强大的工具——scikit-learn 和 Seaborn,通过数据可视化的手段来解决一个经典的分类问题。我们将一起探索如何利用 花萼长度花瓣宽度 这两个关键特征,创建一个能够直观区分不同鸢尾花品种的散点图。

通过阅读这篇文章,你将学会如何从零开始处理原始数据、进行必要的数据预处理(如标签编码)、以及如何利用 Seaborn 绘制出具有专业水准的散点图。无论你是数据科学领域的初学者,还是希望巩固可视化技能的开发者,这篇文章都将为你提供实用的代码示例和深入的逻辑讲解。让我们一起开始这段数据探索的旅程吧。

为什么选择这两个特征?

鸢尾花数据集是机器学习领域的“Hello World”。它包含了三个品种(Iris setosa、Iris virginica 和 Iris versicolor),每个品种各有 50 个样本,共计 150 条记录。数据集包含四个特征:花萼长度花萼宽度花瓣长度花瓣宽度

你可能会问:“既然有四个特征,为什么我们只选择其中两个来画图?” 这是一个非常棒的问题。在多维数据集中,直接可视化所有维度是非常困难的。通过选择特定的特征组合,我们可以观察它们在二维平面上的分布情况。如果选择的特征组合得当,不同类别的样本点会在图上形成明显的聚类。在本教程中,我们将验证“花萼长度”和“花瓣宽度”这一组合是否足以有效地将三种鸢尾花区分开来。

环境准备与数据导入

在开始编写代码之前,我们需要确保环境中已经安装了必要的库。我们将使用 Pandas 进行数据处理,MatplotlibSeaborn 进行可视化,以及 scikit-learn 进行数据预处理。

首先,让我们导入所有必要的包。为了方便起见,我们将使用 Seaborn 内置的数据加载功能,它可以直接从互联网获取数据,这比手动下载 CSV 文件要快得多,也更适合进行快速原型开发。

# 导入必要的库
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
from sklearn import preprocessing

# 设置绘图风格,让图表看起来更专业
sns.set(style="whitegrid", color_codes=True)

# 加载鸢尾花数据集
# Seaborn 内置了该数据集,可以直接加载为 DataFrame
iris_dataframe = sns.load_dataset(‘iris‘)

# 查看数据集的前几行,确保数据加载正确
print("数据集预览:")
print(iris_dataframe.head())

输出示例:

   sepal_length  sepal_width  petal_length  petal_width species
0           5.1          3.5           1.4          0.2  setosa
1           4.9          3.0           1.4          0.2  setosa
2           4.7          3.2           1.3          0.2  setosa
3           4.6          3.1           1.5          0.2  setosa
4           5.0          3.6           1.4          0.2  setosa

数据预处理:理解标签编码

在将数据输入机器学习模型或进行特定类型的可视化之前,我们通常需要将非数值数据转换为数值格式。在 scikit-learn 中,LabelEncoder 是处理这一任务的利器。

鸢尾花数据集中的 species 列包含的是字符串标签(如 ‘setosa‘, ‘versicolor‘, ‘virginica‘)。虽然 Seaborn 在绘图时可以自动处理字符串分类,但为了模拟真实的机器学习预处理流程,或者为了适应某些只接受数值输入的算法,我们需要执行这一步。

LabelEncoder 会将每个唯一的字符串标签映射为一个整数。例如:

  • ‘setosa‘ -> 0
  • ‘versicolor‘ -> 1
  • ‘virginica‘ -> 2

让我们来看看具体的代码实现:

# 初始化 LabelEncoder
le = preprocessing.LabelEncoder()

# 对 ‘species‘ 列进行拟合和转换
# 这一步会学习列中的唯一类别,并将其转换为数字
iris_dataframe[‘species_encoded‘] = le.fit_transform(iris_dataframe[‘species‘])

# 查看转换后的结果
print("
标签编码后的数据集预览:")
print(iris_dataframe.head())

# 查看类别映射关系
print("
编码映射关系:")
for index, label in enumerate(le.classes_):
    print(f"{label} -> {index}")

输出示例:

   sepal_length  sepal_width  petal_length  petal_width    species  species_encoded
0           5.1          3.5           1.4          0.2     setosa                0
1           4.9          3.0           1.4          0.2     setosa                0
...

编码映射关系:
setosa -> 0
versicolor -> 1
virginica -> 2

深入探索:数据分布的初步分析

在绘制散点图之前,作为一个经验丰富的数据分析师,你会想先了解数据的统计特性。我们可以使用 Pandas 的 describe() 方法来快速获取数值特征的统计摘要,例如均值、标准差、最小值和最大值。

# 获取描述性统计信息
desc_stats = iris_dataframe.describe()
print(desc_stats)

这一步能帮助我们识别数据中是否存在异常值,或者不同特征之间的数量级差异是否过大(这通常需要标准化处理)。

核心步骤:创建散点图

现在,让我们进入文章的核心部分——绘制散点图。我们将使用 seaborn.scatterplot 函数。这个函数非常灵活,允许我们通过简单的参数控制来创建高度可定制的图表。

基础散点图绘制

首先,让我们画一个基础的散点图,使用原始的分类标签。我们将在 X 轴放置 INLINECODE2f07ad5e(花萼长度),在 Y 轴放置 INLINECODE406e5898(花瓣宽度)。

# 设置画布大小
plt.figure(figsize=(10, 6))

# x: x轴数据
# y: y轴数据
# hue: 分组依据,根据此列的不同值给点上色
# data: 数据源
# palette: 调色板,‘deep‘ 是 Seaborn 的默认深色主题
sns.scatterplot(data=iris_dataframe, 
                x=‘sepal_length‘, 
                y=‘petal_width‘, 
                hue=‘species‘, 
                palette=‘deep‘, 
                s=60) # s 控制点的大小

# 添加图表标题和轴标签
plt.title(‘鸢尾花分类散点图:花萼长度 vs 花瓣宽度‘, fontsize=16)
plt.xlabel(‘花萼长度‘, fontsize=12)
plt.ylabel(‘花瓣宽度‘, fontsize=12)

# 显示图例
plt.legend(title=‘品种‘, fontsize=10)

# 显示图表
plt.show()

代码深入解析:发生了什么?

  • INLINECODEa3c562f4: 我们在绘图前定义了画布的大小。这非常重要,因为默认的图表尺寸可能太小,导致数据点重叠在一起,或者轴标签被截断。INLINECODEfac16cf5 参数接受一个元组 (宽度, 高度),单位是英寸。
  • INLINECODE3b926da3: 这是散点图中最关键的参数之一。它告诉 Seaborn 根据 INLINECODE5b0d258a 列的值给数据点着色。这使得我们能够直观地看到不同品种在二维平面上的分布情况。
  • palette=‘deep‘: 我们指定了一个调色板。Seaborn 提供了多种调色板(如 ‘bright‘, ‘pastel‘, ‘dark‘ 等),选择一个合适的调色板可以让你的图表更具美感和可读性。

实用见解:观察图表结果

当你运行上述代码后,你会注意到一个非常有趣的现象:

  • Setosa(山鸢尾):在图的左下角形成了一个非常紧凑的聚类。它的花瓣宽度通常较小(接近 0.2 – 0.6),花萼长度也较短。这意味着仅凭这两个特征,我们就几乎可以完美地将 Setosa 与其他品种分开。
  • Versicolor(变色鸢尾):位于中间区域,特征值介于两者之间。
  • Virginica(维吉尼亚鸢尾):位于右上区域,通常具有较大的花瓣宽度和较长的花萼。

然而,你也会发现一个挑战:Versicolor 和 Virginica 在某些区域是重叠的。这意味着,仅靠“花萼长度”和“花瓣宽度”这两个简单的线性特征,可能无法 100% 准确地区分这两个品种。这就是为什么在高级机器学习中,我们需要更复杂的模型或更多维度的特征(如花瓣长度)来提高分类准确率。

进阶技巧:自定义与优化

为了让你绘制的图表更具专业水准,让我们探索一些优化技巧。

1. 使用编码后的数值标签绘图

有时,你可能需要使用编码后的数值(0, 1, 2)而不是字符串作为 hue 参数。这在处理离散化数据或特定算法输出时很常见。

plt.figure(figsize=(10, 6))

# 使用编码后的列进行绘图
sns.scatterplot(data=iris_dataframe, 
                x=‘sepal_length‘, 
                y=‘petal_width‘, 
                hue=‘species_encoded‘, # 使用数值标签
                palette=‘viridis‘, # 使用连续色阶风格
                alpha=0.8) # alpha 控制透明度,处理重叠点很有用

plt.title(‘使用编码标签的散点图‘, fontsize=16)
plt.xlabel(‘花萼长度‘)
plt.ylabel(‘花瓣宽度‘)

# 调整图例,将数字 0, 1, 2 映射回原始名称
handles, labels = plt.gca().get_legend_handles_labels()
# 手动创建图例标签映射
custom_labels = [le.inverse_transform([int(label)])[0] for label in labels]
plt.legend(handles, custom_labels, title=‘品种‘)

plt.show()

2. 添加回归趋势线

为了进一步探索特征之间的关系,我们可以在散点图的基础上添加回归线。Seaborn 的 INLINECODE7ba8a333 或 INLINECODEdef5ad4b 可以轻松实现这一点。这有助于我们判断花萼长度和花瓣宽度之间是否存在线性相关性。

plt.figure(figsize=(10, 6))

# 绘制带有回归线的图
sns.regplot(data=iris_dataframe[iris_dataframe[‘species‘] == ‘setosa‘], 
            x=‘sepal_length‘, y=‘petal_width‘, label=‘Setosa‘)
sns.regplot(data=iris_dataframe[iris_dataframe[‘species‘] == ‘versicolor‘], 
            x=‘sepal_length‘, y=‘petal_width‘, label=‘Versicolor‘)
sns.regplot(data=iris_dataframe[iris_dataframe[‘species‘] == ‘virginica‘], 
            x=‘sepal_length‘, y=‘petal_width‘, label=‘Virginica‘)

plt.title(‘带趋势线的散点图分析‘, fontsize=16)
plt.legend()
plt.show()

3. 多维数据的成对比较

虽然我们专注于两个特征,但在实际项目中,了解所有特征两两之间的关系至关重要。sns.pairplot 是一个强大的工具,它一次性绘制所有特征的配对图。

# 绘制配对图
# 这将生成一个矩阵,对角线是直方图,其他位置是散点图
sns.pairplot(iris_dataframe, hue=‘species‘, height=2.5, palette=‘husl‘)
plt.suptitle(‘鸢尾花数据集多维特征分析‘, y=1.02, fontsize=18)
plt.show()

常见错误与故障排除

在进行数据可视化的过程中,你可能会遇到一些常见问题。以下是一些解决方案:

  • 中文显示乱码:如果你在图表标题或标签中使用中文字符,发现它们显示为方框(□),这是因为 Matplotlib 默认不支持中文字体。我们可以通过以下代码修复:
  •     plt.rcParams[‘font.sans-serif‘] = [‘SimHei‘] # 用来正常显示中文标签
        plt.rcParams[‘axes.unicode_minus‘] = False # 用来正常显示负号
        
  • 数据类型错误:如果 INLINECODEe06f7807 报错,请检查传入的是否确实是 Pandas Series 或列表。如果你传入的是一个 DataFrame 而不是 Series,代码可能会失败。使用 INLINECODEad33add4 而不是 iris_dataframe[[‘species‘]]
  • 过拟合:虽然在可视化中不常提及,但如果你试图通过复杂的图形调整来强行分离 Versicolor 和 Virginica 的重叠区域,请记住这可能导致误导性的结论。在重叠区域,简单的线性分类器可能会有很高的误判率,这时候可能需要支持向量机(SVM)或随机森林等非线性模型。

性能优化与最佳实践

当处理比 Iris 数据集大得多的数据集(例如数百万行)时,直接使用 sns.scatterplot 可能会变得非常慢,甚至导致浏览器或 IDE 崩溃。

  • 采样:对于大数据集,在绘图前随机采样一部分数据(例如 data.sample(1000))来快速洞察分布。
  • 透明度:使用 INLINECODEb4233c6b 参数。当数据点非常密集时,设置 INLINECODE4ab2f7c6 可以让你看到数据的密度分布,深色的区域代表数据点重叠严重。
  • 避免过度绘图:如果你的图表中充满了数万个点,考虑使用 Hexbin 图(二维直方图)或 2D 密度图,它们更适合可视化海量连续数据的分布。

总结

在这篇文章中,我们不仅学会了如何使用 Python 绘制简单的散点图,还深入探讨了从数据导入、清洗、编码到最终可视化分析的完整流程。我们利用 INLINECODE22161953 的 INLINECODE2bb2bec6 处理了分类数据,并利用 seaborn 的强大功能,直观地展示了鸢尾花数据集中不同品种基于花萼长度和花瓣宽度的分布差异。

我们通过实际代码发现,虽然 Setosa 品种很容易被区分,但 Versicolor 和 Virginica 在这两个特征上存在重叠,这为我们在构建分类模型时提供了重要的参考依据。

下一步建议

既然你已经掌握了这些基础知识,我建议你尝试以下挑战来进一步提升技能:

  • 尝试不同的特征组合:绘制 INLINECODE05d97778 vs INLINECODE7f328654,看看是否能得到更好的分离效果?
  • 探索其他数据集:下载一个包含更多列的真实世界数据集(如房价预测或客户细分数据),尝试找出两个最具区分度的特征进行可视化。
  • 动手实现分类器:使用 Scikit-learn 的 INLINECODE3cc48bad 或 INLINECODEfe67af6b,仅仅基于我们绘图用的这两个特征,训练一个模型并计算其准确率,验证我们在图表中的直观判断是否准确。

希望这篇教程能为你打开数据可视化的大门,继续在数据的海洋中探索吧!

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。如需转载,请注明文章出处豆丁博客和来源网址。https://shluqu.cn/40264.html
点赞
0.00 平均评分 (0% 分数) - 0