手写数字数据集的流形学习技术比较

机器学习领域,降维技术是探索高维数据集结构的重要工具。本文将展示如何在手写数字数据集上应用多种流形学习技术,并通过可视化手段比较它们的性能和特点。手写数字数据集是一个经典的数据集,包含了1797个8x8像素的手写数字图像,每个图像可以看作是64维的特征向量。

首先,从手写数字数据集中加载数据,并只使用前六个类别的数据。然后,使用不同的流形学习技术对数据进行降维,并将原始数据投影到降维后的空间中。通过比较不同技术生成的投影,可以观察到手写数字在降维空间中的分布情况,以及它们是否能够保持原有的类别结构。

from sklearn.datasets import load_digits from sklearn.preprocessing import MinMaxScaler import matplotlib.pyplot as plt import numpy as np from matplotlib import offsetbox # 加载手写数字数据集 digits = load_digits(n_class=6) X, y = digits.data, digits.target n_samples, n_features = X.shape n_neighbors = 30 # 绘制前100个手写数字 fig, axs = plt.subplots(nrows=10, ncols=10, figsize=(6, 6)) for idx, ax in enumerate(axs.ravel()): ax.imshow(X[idx].reshape((8, 8)), cmap=plt.cm.binary) ax.axis('off') _ = fig.suptitle("手写数字数据集的部分样本", fontsize=16)

接下来,定义一个辅助函数来绘制数据的嵌入投影。这个函数将使用不同的流形学习技术对数据进行降维,并在二维空间中绘制出每个数字的投影点。通过这种方式,可以直观地比较不同技术的效果,例如它们是否能够将不同类别的数字聚集在一起,或者在降维空间中是否能够保持数字的形状特征。

def plot_embedding(X, title): fig, ax = plt.subplots() X = MinMaxScaler().fit_transform(X) for digit in digits.target_names: ax.scatter(*X[y == digit].T, marker=f"${digit}$", s=60, color=plt.cm.Dark2(digit), alpha=0.425, zorder=2) shown_images = np.array([[1.0, 1.0]]) for i in range(X.shape[0]): dist = np.sum((X[i] - shown_images) ** 2, 1) if np.min(dist) < 4e-3: continue shown_images = np.concatenate([shown_images, [X[i]]], axis=0) imagebox = offsetbox.AnnotationBbox(offsetbox.OffsetImage(digits.images[i], cmap=plt.cm.gray_r), X[i]) imagebox.set(zorder=1) ax.add_artist(imagebox) ax.set_title(title) ax.axis('off')

在比较不同的流形学习技术时,需要注意以下几点:首先,随机森林嵌入(RandomTreesEmbedding)并不是一种典型的流形学习方法,因为它首先学习一个高维表示,然后应用降维方法。然而,它在将数据集转换为类别线性可分的表示中非常有用。其次,线性判别分析(LinearDiscriminantAnalysis)和邻域成分分析(NeighborhoodComponentsAnalysis)是监督降维方法,它们利用了提供的数据标签,与其他方法不同。此外,t-SNE在这个例子中使用PCA生成的嵌入进行初始化,以确保嵌入的全局稳定性,即嵌入结果不依赖于随机初始化。

from sklearn.decomposition import TruncatedSVD from sklearn.discriminant_analysis import LinearDiscriminantAnalysis from sklearn.ensemble import RandomTreesEmbedding from sklearn.manifold import MDS, TSNE, Isomap, LocallyLinearEmbedding, SpectralEmbedding from sklearn.neighbors import NeighborhoodComponentsAnalysis from sklearn.pipeline import make_pipeline from sklearn.random_projection import SparseRandomProjection embeddings = { "随机投影嵌入": SparseRandomProjection(n_components=2, random_state=42), "截断SVD嵌入": TruncatedSVD(n_components=2), "线性判别分析嵌入": LinearDiscriminantAnalysis(n_components=2), "Isomap嵌入": Isomap(n_neighbors=n_neighbors, n_components=2), "标准LLE嵌入": LocallyLinearEmbedding(n_neighbors=n_neighbors, n_components=2, method="standard"), "修改LLE嵌入": LocallyLinearEmbedding(n_neighbors=n_neighbors, n_components=2, method="modified"), "Hessian LLE嵌入": LocallyLinearEmbedding(n_neighbors=n_neighbors, n_components=2, method="hessian"), "LTSA LLE嵌入": LocallyLinearEmbedding(n_neighbors=n_neighbors, n_components=2, method="ltsa"), "MDS嵌入": MDS(n_components=2, n_init=1, max_iter=120, n_jobs=2), "随机森林嵌入": make_pipeline(RandomTreesEmbedding(n_estimators=200, max_depth=5, random_state=0), TruncatedSVD(n_components=2)), "谱嵌入": SpectralEmbedding(n_components=2, random_state=0, eigen_solver="arpack"), "t-SNE嵌入": TSNE(n_components=2, max_iter=500, n_iter_without_progress=150, n_jobs=2, random_state=0), "NCA嵌入": NeighborhoodComponentsAnalysis(n_components=2, init="pca", random_state=0), } projections, timing = {}, {} for name, transformer in embeddings.items(): if name.startswith("线性判别分析"): data = X.copy() data.flat[::X.shape[1] + 1] += 0.01 # 使X可逆 else: data = X print(f"计算{name}...") start_time = time() projections[name] = transformer.fit_transform(data, y) timing[name] = time() - start_time # 绘制每种方法的结果投影 for name in timing: title = f"{name} (时间 {timing[name]:.3f}s)" plot_embedding(projections[name], title) plt.show()
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485