目录

机器学习基于t-SNE的MNIST数据集可视化探索

【机器学习】基于t-SNE的MNIST数据集可视化探索

一、前言

在机器学习和数据科学领域,高维数据的可视化是一个极具挑战但又至关重要的问题。高维数据难以直观地理解和分析,而有效的可视化方法能够帮助我们发现数据中的潜在结构、模式和关系。本文以经典的MNIST手写数字数据集为例,探讨如何利用t-分布随机邻域嵌入(t-SNE)这一强大的降维技术,将高维的图像数据降维到二维空间,并进行可视化展示。通过本文,我们将深入了解t-SNE的原理、算法步骤,以及如何在Python中实现并应用它,从而更好地理解和探索高维数据的内在特性。


二、 技术与原理简介

在深入探讨t-SNE之前,我们首先需要区分机器学习中的两大主要范畴:监督学习和无监督学习。

1. 监督学习

监督学习是指在已知输入数据和对应标签的情况下,训练模型学习输入与输出之间的映射关系。模型通过学习大量的带标签数据,能够对新的、未见过的数据进行预测或分类。常见的监督学习算法包括:

  • 线性回归: 用于预测连续型变量。
  • 逻辑回归: 用于分类问题。
  • 支持向量机 (SVM): 用于分类和回归问题,尤其擅长处理高维数据。
  • 决策树: 基于树状结构进行决策,易于理解和解释。
  • 随机森林: 集成多个决策树,提高预测的准确性和鲁棒性。
  • 神经网络: 模拟人脑神经元结构,能够学习复杂的非线性关系。

2. 无监督学习

无监督学习是指在没有标签的情况下,训练模型发现数据中的潜在结构和模式。模型通过分析数据的内在特征,能够进行聚类、降维、关联规则挖掘等任务。常见的无监督学习算法包括:

  • 聚类: 将数据划分为不同的簇,使得同一簇内的数据相似度较高,不同簇之间的数据相似度较低。常见的聚类算法包括K-means、层次聚类、DBSCAN等。
  • 降维: 将高维数据降维到低维空间,同时尽可能保留数据的关键信息。常见的降维算法包括主成分分析 (PCA)、t-SNE、UMAP等。
  • 关联规则挖掘: 发现数据中不同项之间的关联关系,例如购物篮分析。

3. 监督学习与无监督学习的区别

https://i-blog.csdnimg.cn/direct/6671f326daf4403283e344b0f9dfaf46.png

4. MNIST数据集简介

MNIST (Modified National Institute of Standards and Technology database) 是一个经典的手写数字数据集,广泛应用于机器学习和深度学习领域。它包含60,000个训练样本和10,000个测试样本,每个样本都是一个28x28像素的灰度图像,代表0到9之间的手写数字。

https://i-blog.csdnimg.cn/direct/1e86f074b31247f4bb72517110c0be58.png

4.1 数据格式

MNIST数据集通常以两种格式提供:

  • 图像格式: 每个样本都是一个图像文件,例如PNG或JPEG格式。
  • 数值格式: 每个样本都被转换为一个784维的向量,其中每个元素代表一个像素的灰度值 (0到255)。

4.2 数据集特点

  • 规模适中: MNIST数据集的规模适中,既可以用于快速原型验证,又可以用于训练复杂的模型。
  • 易于获取: MNIST数据集可以从多个来源免费获取,例如Scikit-learn、TensorFlow等。
  • 广泛应用: MNIST数据集被广泛应用于各种机器学习和深度学习算法的评估和比较。

5. t-SNE算法原理与数学推导

5.1 算法核心思想

t-SNE(t-Distributed Stochastic Neighbor Embedding)是一种非线性降维技术,通过以下步骤实现高维数据到低维空间的映射:

  1. 计算高维相似度 :在原始空间中,计算每对样本间的相似度
  2. 构建低维嵌入空间 :在目标空间(如2D)中,通过优化使相似度分布匹配
  3. 梯度下降优化 :最小化两空间分布的KL散度

5.2 数学公式详解

5.2.1 高维相似度计算

对原始空间中的样本对(𝑥𝑖,𝑥𝑗) ,定义条件概率:

https://i-blog.csdnimg.cn/direct/03c8dd8281e94510936e0fd549c48842.png

其中𝜎𝑖 ​为高斯核带宽,通过二分查找确定以满足** perplexity **参数(控制邻域大小)。

5.2.2 低维相似度建模

在目标空间中,定义联合概率:

https://i-blog.csdnimg.cn/direct/47940b53ef2444ee84cb78e32bb82457.png

采用t-分布(自由度为1的Student分布)以增强对异常值的鲁棒性。

5.2.3 目标函数优化

通过最小化KL散度实现分布匹配:

https://i-blog.csdnimg.cn/direct/ab630535d86c403397bdc12a520f01d2.png

其中

https://i-blog.csdnimg.cn/direct/c24c16a797924b1a879808161d3ccad1.png

优化过程使用梯度下降:

https://i-blog.csdnimg.cn/direct/559a07f71c634e09869a6648d5fcc6cc.png

5.3 算法步骤流程

  1. 参数初始化 :设置降维维度(如2D)、perplexity(通常5-50)、学习率等
  2. 高维相似度计算 :为每个样本计算条件概率矩阵𝑃P
  3. 低维初始化 :随机生成初始嵌入坐标𝑌Y
  4. 梯度下降优化 :迭代更新𝑌Y以最小化KL散度
  5. 结果输出 :返回低维坐标矩阵

三、代码详解

本文的代码主要分为以下几个部分:

1. 导入库

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import seaborn as sns
from sklearn import datasets
from sklearn import manifold
%matplotlib inline

说明

  • import matplotlib.pyplot as plt
    导入matplotlib库,用于绘制图像。
  • import numpy as np
    导入numpy库,用于进行数值计算。
  • import pandas as pd
    导入pandas库,用于数据处理。
  • import seaborn as sns
    导入seaborn库,用于数据可视化。
  • from sklearn import datasets
    导入sklearn库中的datasets模块,用于加载数据集。
  • from sklearn import manifold
    导入sklearn库中的manifold模块,用于降维。
  • %matplotlib inline
    在Jupyter Notebook中显示图像。

2. 加载数据

# 加载数据
data = datasets.fetch_openml('mnist_784', version=1, return_X_y=True)
pixel_values, targets = data
targets = targets.astype(int)

# 将DataFrame转换为numpy数组以便更容易操作
# 如果pixel_values已经是numpy数组,这一步可以跳过
if isinstance(pixel_values, pd.DataFrame):
    pixel_values_array = pixel_values.values
else:
    pixel_values_array = pixel_values

说明

  • data = datasets.fetch_openml('mnist_784', version=1, return_X_y=True)
    使用 datasets.fetch_openml 函数加载MNIST数据集。 'mnist_784' 表示数据集的名称, version=1 表示数据集的版本, return_X_y=True 表示返回输入数据和标签。
  • pixel_values, targets = data
    将返回的数据解包为 pixel_valuestargetspixel_values 包含图像的像素值, targets 包含图像的标签。
  • targets = targets.astype(int)
    将标签转换为整数类型。
  • if isinstance(pixel_values, pd.DataFrame):
    检查 pixel_values 是否为pandas DataFrame类型。
  • pixel_values_array = pixel_values.values
    如果 pixel_values 为pandas DataFrame类型,则将其转换为numpy数组。
  • else: pixel_values_array = pixel_values
    否则,直接使用 pixel_values

3. 显示单个图像

# 显示单个图像
single_image = pixel_values_array[1].reshape(28, 28)
plt.imshow(single_image, cmap='gray')

说明

  • single_image = pixel_values_array[1].reshape(28, 28)
    选择第一个图像,并将其reshape为28x28的矩阵。
  • plt.imshow(single_image, cmap='gray')
    使用 plt.imshow 函数显示图像, cmap='gray' 表示使用灰度颜色映射。

4. t-SNE降维

# t-SNE降维
tsne = manifold.TSNE(n_components=2, random_state=42)
transformed_data = tsne.fit_transform(pixel_values_array[:3000])

说明

  • tsne = manifold.TSNE(n_components=2, random_state=42)
    创建一个t-SNE对象。 n_components=2 表示将数据降维到二维空间, random_state=42 表示设置随机种子,保证结果的可重复性。
  • transformed_data = tsne.fit_transform(pixel_values_array[:3000])
    使用 fit_transform 函数对数据进行降维。这里只使用了前3000个样本,因为t-SNE的计算复杂度较高。

5. 创建DataFrame用于可视化

# 创建DataFrame用于可视化
tsne_df = pd.DataFrame(
    np.column_stack((transformed_data, targets[:3000])),
    columns=["x", "y", "targets"]
)
tsne_df.loc[:, "targets"] = tsne_df.targets.astype(int)

说明

  • tsne_df = pd.DataFrame(...)
    创建一个pandas DataFrame对象,用于存储降维后的数据和标签。
  • np.column_stack((transformed_data, targets[:3000]))
    将降维后的数据和标签按列拼接在一起。
  • columns=["x", "y", "targets"]
    设置DataFrame的列名。
  • tsne_df.loc[:, "targets"] = tsne_df.targets.astype(int)
    将DataFrame中的标签转换为整数类型。

6. 可视化

# 可视化
# 注意:在新版本的seaborn中,size参数已更改为height
try:
    grid = sns.FacetGrid(tsne_df, hue="targets", size=8)
except TypeError:
    grid = sns.FacetGrid(tsne_df, hue="targets", height=8)
    
grid.map(plt.scatter, "x", "y").add_legend()

说明

  • grid = sns.FacetGrid(tsne_df, hue="targets", size=8)
    创建一个seaborn FacetGrid对象,用于可视化降维后的数据。 hue="targets" 表示使用标签作为颜色编码, size=8 表示设置图像的大小。
  • grid.map(plt.scatter, "x", "y").add_legend()
    使用 plt.scatter 函数绘制散点图, "x""y" 表示散点图的横坐标和纵坐标, add_legend() 表示添加图例。

7. 完整代码

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import seaborn as sns
from sklearn import datasets
from sklearn import manifold
%matplotlib inline

# 加载数据
data = datasets.fetch_openml('mnist_784', version=1, return_X_y=True)
pixel_values, targets = data
targets = targets.astype(int)

# 将DataFrame转换为numpy数组以便更容易操作
# 如果pixel_values已经是numpy数组,这一步可以跳过
if isinstance(pixel_values, pd.DataFrame):
    pixel_values_array = pixel_values.values
else:
    pixel_values_array = pixel_values

# 显示单个图像
single_image = pixel_values_array[1].reshape(28, 28)
plt.imshow(single_image, cmap='gray')

# t-SNE降维
tsne = manifold.TSNE(n_components=2, random_state=42)
transformed_data = tsne.fit_transform(pixel_values_array[:3000])

# 创建DataFrame用于可视化
tsne_df = pd.DataFrame(
    np.column_stack((transformed_data, targets[:3000])),
    columns=["x", "y", "targets"]
)
tsne_df.loc[:, "targets"] = tsne_df.targets.astype(int)

# 可视化
# 注意:在新版本的seaborn中,size参数已更改为height
try:
    grid = sns.FacetGrid(tsne_df, hue="targets", size=8)
except TypeError:
    grid = sns.FacetGrid(tsne_df, hue="targets", height=8)
    
grid.map(plt.scatter, "x", "y").add_legend()

https://i-blog.csdnimg.cn/direct/fea1ab0e85ad45c5866311bd87b3d5de.png

https://i-blog.csdnimg.cn/direct/b6da1b126227437db51753060b2c1d32.png


四、总结与思考

本文以MNIST数据集为例,详细介绍了如何使用t-SNE进行高维数据可视化。通过t-SNE降维,我们可以将784维的图像数据降维到二维空间,并在散点图上清晰地看到不同数字之间的分布情况。

t-SNE是一种强大的降维技术,但也有一些局限性:

  • 计算复杂度高: t-SNE的计算复杂度为O(n^2),对于大规模数据集,计算时间会非常长。
  • 参数敏感: t-SNE的性能受到参数的影响,例如困惑度 (perplexity) 和学习率 (learning_rate)。
  • 全局结构失真: t-SNE主要关注局部结构,可能会导致全局结构失真。

在实际应用中,我们需要根据具体情况选择合适的降维技术。对于大规模数据集,可以考虑使用PCA或UMAP等更高效的算法。对于需要保留全局结构的场景,可以考虑使用Isomap或LLE等算法。


【作者声明】

本文内容基于作者对基于t-SNE的MNIST数据集可视化探索实现过程的实验与总结,所有数据和代码均为原创。文章中的观点仅代表个人见解,供读者参考交流。若有任何问题或建议,欢迎在评论区留言讨论,共同促进技术进步。


【关注我们】

如果您对神经网络、群智能算法及人工智能技术感兴趣,欢迎点赞、收藏并转发,与更多朋友一起探讨与交流!