2026a

# 流形学习算法对比


这是一个展示使用不同流形学习方法在 S 形曲面数据集上进行降维的示例。在本案例中,使用流形学习算法对数据降维,同时保留数据点之间的关系,达到展开数据集的效果,本案例使用的流形学习方法包括:

  • Locally Linear Embeddings
    • Standard
    • LTSA
    • Hessian
    • Modified
  • Isomap Embedding
  • Multidimensional scaling
  • Spectral embedding for non-linear dimensionality reduction
  • T-distributed Stochastic Neighbor Embedding

# 实验准备

# 数据准备

首先,我们从机器学习工具箱中导入 S Curve 数据集。

using TyMachineLearning
S_points, S_color = get_curve()  # 获取数据集

使用图形工具箱对数据集进行可视化:

using TyPlot
scatter3(S_points[:, 1], S_points[:, 2], S_points[:, 3], c=S_color, s=50, filled=true)

可以看到,我们的数据集呈现出一个 S 型曲面的形状,其中的数据点在不同的地方有着不一样的密度分布。

# 绘图工具准备

在本实验中,绘制的图形较多,为了更方便地进行绘图,我们定义一个函数来调用图形工具箱内的 scatter 二维散点图工具,来简化绘图的过程:

""" 
    plot_2d(data, fig, fig_title): 使用 TyPlot 绘制降维后的 2D 散点图

    args: 
        data: 用于绘图的 2D 数据
        fig: 用于绘图的画布
        fig_title: 图标题
        sub_pos(optional): 子图位置(横向数量,纵向数量,第 i 个子图)
"""
function plot_2d(data, fig, fig_title; sub_pos=(0, 0, 0))
    if sub_pos != (0, 0, 0)
        subplot(sub_pos[1], sub_pos[2], sub_pos[3])
    end
    figure(fig)
    scatter(data[:, 1], data[:, 2]; c=S_color, s=50, filled=true)
    title(fig_title)
    return true
end

# 定义流形学习模型

流形学习是一种非线性降维的方法。用于此任务的算法基于这样一个思想:许多数据集的维度只是人为地被提高了,其实其数据之间存在更低维的数据关系。

# Locally Linear Embeddings

局部线性嵌入(LLE)可以被认为是一系列局部主成分分析,它们在全局进行比较,以找到最佳的非线性嵌入。本例中将要测试 4 种不同的 LLE 模型,因此,我们首先定义一个函数来创建这 4 种模型,该函数返回一个字典,该字典包括了 4 种模型计算的不同结果:

""" 
    build_lle_models(data): 使用 4 种 LLE 模型拟合输入数据,返回降维后的结果。

    args:
        data: 输入的数据,用于 mainfold 模型计算
    return:
        返回一个字典,包含了例子用到的四个模型返回的降维之后的数据
        Dict(
            "lle_standard" => lle_standard,
            "lle_ltsa" => lle_ltsa,
            "lle_hessian" => lle_hessian,
            "lle_mod" => lle_mod,
        )
"""
function build_lle_models(data)
    # 定义一个函数来构建并训练 4 种 LLE 模型
    print("-> Computing standard...\n")
    sd_embedding, ev = fitLocallyLinearEmbedding(data; n_neighbors=12, eigen_solver="auto")
    lle_standard = sd_embedding.embedding_
    print("-> Computing ltsa...\n")
    lle_ltsa = fitltsaEmbedding(data).fit_transform(data)
    print("-> Computing hessian...\n")
    lle_hessian = fitHessianEigenmapping(data).fit_transform(data)
    print("-> Computing modified...\n")
    lle_mod = fitMLLEmbedding().fit_transform(data)

    return Dict(
        "lle_standard" => lle_standard,
        "lle_ltsa" => lle_ltsa,
        "lle_hessian" => lle_hessian,
        "lle_mod" => lle_mod,
    )
end

接下来,我们调用这个函数,得到 4 个 LLE 模型的计算结果:

# 使用 LLE 模型对数据进行降维
lle_models = build_lle_models(S_points)

在得到计算结果后,使用前面我们定义的 plot_2d 函数绘制图像,对计算结果进行可视化。此处我们使用循环结构,对结果字典中的各个模型结果进行遍历,再在每次循环中调用 plot_2d 函数绘制各个模型的可视化结果:

fig = figure(; figsize=[7.4, 5.8])
global position = 0  # 用于确定子图位置
for key in keys(lle_models)
    global position += 1
    plot_2d(lle_models[key], fig, key; sub_pos=(2, 2, position))
end

# Isomap Embedding

通过等距映射进行非线性降维。Isomap 寻求一个低维嵌入,保持所有点之间的测地距离。现在,我们使用机器学习工具箱中的 Isomap 模型对数据进行降维:

# 使用 Isomap 模型对数据进行降维
print("-> Computing isomap...\n")
isomap_embedding, isomap_ev = fitIsomap(S_points)
isomap_result = isomap_embedding.embedding_

plot_2d(isomap_result, figure(), "Isomap Embedding")

# Multidimensional scaling

多维缩放(MDS)寻求数据的低维表示,使得距离尽可能地保持原始高维空间中的距离。通常,MDS 是一种用于分析相似性或差异性数据的技术。

# 使用 MDS 模型对数据进行降维
print("-> Computing MDS...\n")
mds_embedding, ts = cmdscale(S_points)
mds_result = mds_embedding.fit_transform(S_points)

plot_2d(mds_result, figure(), "MDS Embedding")

# Spectral embedding for non-linear dimensionality reduction

这个实现使用拉普拉斯特征映射,它通过对图拉普拉斯算子进行谱分解,找到数据的低维表示。

# 使用 Spectral 模型对数据进行降维
print("-> Computing spectral...\n")
spectral_embedding = fitSpectralEmbedding("nearest_neighbors")
spectral_result = spectral_embedding.fit_transform(S_points)

plot_2d(spectral_result, figure(), "Specture Result")

# T-distributed Stochastic Neighbor Embedding

它将数据点之间的相似性转换为联合概率,并试图最小化低维嵌入和高维数据的联合概率之间的 Kullback-Leibler 散度。t-SNE 有一个非凸的代价函数,即不同的初始化会得到不同的结果。

# 使用 tsne 模型对数据进行降维
print("-> Computing tsne...\n")
tsne_embedding = tsne(; init="random")
tsne_result = tsne_embedding.fit_transform(S_points)

plot_2d(tsne_result, figure(), "t-SNE Result")

由于函数运行过程中存在随机性,因此上述模型降维效果可能会略有差异。