UMAP非线性降维算法

文章目录


UMAP,全称Uniform Manifold Approximation and Projection(均匀流形近似与投影),是一种基于流形学习理论的非线性降维算法。与传统的线性降维方法PCA相比,UMAP在保留数据的拓扑结构和局部邻域关系方面具有独特优势,尤其适用于单细胞测序、图像分析、自然语言处理等领域。本文将从原理、与PCA的关键区别、实现步骤、代码示例到参数调优,来介绍UMAP的使用方法与适用场景。

一、UMAP的核心思想

UMAP假设高维数据采样自一个低维流形,且该流形上的数据分布在局部是均匀的(通过自适应距离归一化实现),而不是整个流形上均匀分布。

  • 流形学习:认为高维数据实际上分布在低维流形上,降维的目标是发掘这种潜在的流形结构。
  • 保局部结构:UMAP优先保留数据的局部邻域关系,让原始空间中邻近的点在降维后依然靠近。
  • 兼顾全局:UMAP相比 t-SNE能更好地避免将全局结构撕裂成多个孤立的簇,从而在可视化中呈现出更连贯的全局布局。

UMAP通过构建一个加权的k-近邻图来表示高维数据的拓扑结构,然后通过优化过程在低维空间中学习一个相似的图结构,最终得到降维后的表示。

二、降维的动机与UMAP的优势

在对比之前,先明确降维的通用动机:

维度灾难:高维数据中样本稀疏,模型需要更多样本才能有效训练。

可视化需求:人类无法直观理解超过3维的数据分布。

去冗余:许多特征间存在高度相关性。

在PCA的好处基础上,UMAP提供了额外的优势:

优势 说明
处理非线性关系 PCA只能捕捉线性变化(如直线趋势),UMAP能发现弯曲、环形等复杂结构
保留局部拓扑 优先保证相似样本在降维后依然相近,适合发现子类别
计算效率高 相比t-SNE,UMAP速度更快,能处理百万级样本
可扩展性强 支持监督降维、预计算k-近邻图等高级功能

三、PCA与UMAP的核心区别

算法本质对比

方面 PCA UMAP
数学原理 线性投影,最大化方差 流形学习,保留拓扑结构
保留关系 全局方差结构 局部邻域关系 + 部分全局结构
数据假设 线性关系、无强离群点 局部均匀分布在低维流形上
输出解释 各主成分是原始特征的线性组合 坐标无直接物理解释
可重复性 确定性算法,结果稳定 随机初始化,需设随机种子确保稳定

何时选择哪种算法

场景 推荐算法 原因
数据呈线性结构(如经济指标) PCA 简单高效,解释性强
需要保留全局方差结构 PCA 主成分贡献率明确
特征工程/预处理 PCA 降维后可逆,可用于重构
可视化高维聚类(如单细胞) UMAP 保留局部关系,簇间分离效果好
探索非线性结构 UMAP 发现流形结构
大规模数据(>10万样本) UMAP 计算效率高

四、UMAP降维的步骤

UMAP的核心流程分为四个阶段:

1. 构建加权k-近邻图

在高维空间中为每个点找到k个最近邻(k由n_neighbors参数指定),边的权重基于局部距离自适应调整。

2. 构建模糊拓扑表示

将k-近邻图转换为模糊单纯形集,形成对数据拓扑结构的数学表示。

3. 初始化低维嵌入

通常使用谱嵌入对低维坐标进行初始化(也可选择随机初始化或PCA初始化)。

谱嵌入是一种利用图论和线性代数(特征值分解)来寻找数据最佳低维表示的方法。

4. 优化嵌入

采用随机梯度下降(SGD)优化低维嵌入,使其模糊拓扑结构与高维表示尽可能相似。

五、使用scikit-learn实现UMAP

安装

bash 复制代码
pip install umap-learn

基础用法:可视化

python 复制代码
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import load_digits
from sklearn.preprocessing import StandardScaler
import umap

# 1. 加载数据(使用 scikit-learn 自带的 digits 数据集)
print("加载 digits 数据集...")
digits = load_digits()
X = digits.data          # (1797, 64) - 8x8 图像展平
y = digits.target        # (1797,) - 0-9 的数字标签

print(f"原始数据形状: {X.shape}")      # (1797, 64)
print(f"样本数量: {X.shape[0]}")
print(f"特征维度: {X.shape[1]}")
print(f"类别数量: {len(np.unique(y))}")

# 2. 标准化(UMAP 对尺度敏感,建议标准化)
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

# 3. 执行 UMAP 降维
print("执行 UMAP 降维...")
reducer = umap.UMAP(
    n_neighbors=15,      # 局部邻域大小
    n_components=2,      # 降维目标维度
    min_dist=0.1,        # 嵌入点间最小距离
    random_state=42      # 确保可重复性
)

X_umap = reducer.fit_transform(X_scaled)
print(f"降维后形状: {X_umap.shape}")  # (1797, 2)

# 4. 可视化结果
plt.figure(figsize=(12, 10))
scatter = plt.scatter(X_umap[:, 0], X_umap[:, 1], 
                       c=y, cmap='tab10', s=15, alpha=0.7)
plt.colorbar(scatter, ticks=range(10))
plt.title('UMAP visualization of Digits dataset (1,797 samples, 64-dim)', fontsize=14)
plt.xlabel('UMAP Component 1')
plt.ylabel('UMAP Component 2')
plt.tight_layout()
plt.show()

# 5. 打印一些统计信息
print(f"降维完成!")
print(f"原始维度: {X.shape[1]} → 降维后维度: {X_umap.shape[1]}")
print(f"UMAP 运行参数: n_neighbors={reducer.n_neighbors}, min_dist={reducer.min_dist}")

UMAP 建议进行标准化(尤其是使用欧氏距离时),除非所有特征已在可比尺度上。

在机器学习流水线中使用UMAP

与PCA类似,UMAP也可以无缝集成到scikit-learn的Pipeline中:

python 复制代码
import numpy as np
from sklearn.pipeline import Pipeline
from sklearn.svm import SVC
from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.preprocessing import StandardScaler
from sklearn.datasets import make_swiss_roll
import umap

# 1. 构造非线性数据集(瑞士卷)加上随机噪声
np.random.seed(42)
n_samples = 500
X, t = make_swiss_roll(n_samples=n_samples, noise=0.5, random_state=42)
# 添加大量随机噪声特征(100个无用特征)
X_noise = np.random.randn(n_samples, 100) * 2
X = np.hstack([X, X_noise])  # 3维结构 + 100维噪声 = 103维
# 二分类标签:基于瑞士卷位置
y = (t > np.median(t)).astype(int)

X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.3, random_state=42
)

# 标准化(重要)
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

# 2. 不使用UMAP(在高维噪声数据上训练)
svc = SVC(kernel='rbf', random_state=42, C=1.0)
svc.fit(X_train_scaled, y_train)
print(f"原始数据准确率: {svc.score(X_test_scaled, y_test):.3f}")

# 3. 使用UMAP降维
pipeline = Pipeline([
    ('scaler', StandardScaler()),
    ('umap', umap.UMAP(random_state=42, n_neighbors=15)),
    ('svc', SVC(kernel='rbf', random_state=42))
])

param_grid = {
    'umap__n_components': [2, 5, 10, 20],
    'svc__C': [0.1, 1, 10]
}

grid_search = GridSearchCV(pipeline, param_grid, cv=5, scoring='accuracy')
grid_search.fit(X_train, y_train)

print(f"UMAP降维后最佳交叉验证准确率: {grid_search.best_score_:.3f}")
print(f"最佳参数: {grid_search.best_params_}")

# 在测试集上评估
test_score = grid_search.best_estimator_.score(X_test, y_test)
print(f"测试集准确率: {test_score:.3f}")

在高维(103维)但样本量有限(500个)的场景下,UMAP可以作为流水线中的特征提取步骤,通过网格搜索自动选择最优的降维维度和分类器参数。

六、UMAP的核心参数详解

参数 含义 典型值范围 效果
n_neighbors 局部邻域大小 5-100 越小越关注局部细节;越大越保留全局结构
n_components 降维维度 2(可视化)至100 目标嵌入维度
min_dist 嵌入点间最小距离 0.0-0.5 min_dist 越小:局部结构更紧凑,但全局结构可能被拉长;min_dist 越大:嵌入更紧凑,但可能模糊簇边界。
metric 距离度量 'euclidean', 'cosine', 'manhattan' 根据数据类型选择
random_state 随机种子 任意整数 关键:确保结果可重复

n_neighbors参数对结果的影响

n_components 定义了数据经由 UMAP 算法映射后的目标低维特征空间的维度数。其选择原则主要取决于下游任务的需求与数据内在流形的复杂度。

在该数据集上的实验表明:

  • n_neighbors=2:嵌入完全失效,点散落成松散圆云,无法识别簇
  • n_neighbors=15 :形成稳定、分离良好的簇,全局结构清晰(推荐起点

选择n_components的一般原则

目标 推荐n_components 说明
可视化(2D散点图) 2 便于直接观察
可视化(3D交互图) 3 可用plotly等库旋转查看
特征提取(替代PCA) 10-100 根据下游任务交叉验证选择
保留局部结构 较低(2-5) 强制压入低维
保留更多信息 较高(30-100) 减少信息损失

七、理解UMAP的嵌入结果

与PCA不同,UMAP的低维坐标没有直接的物理解释。PCA的每个主成分是原始特征的线性组合,可以通过载荷(loadings)解释;而UMAP的坐标仅是嵌入空间中点的位置,用于显示相似性关系。

解读方式

  1. 相对距离有意义:点越接近,表示原始空间中越相似
  2. 簇结构有意义:不同颜色的簇表示不同类型的样本
  3. 距离没有绝对尺度 :UMAP的min_dist参数会压缩或分散点云

提取UMAP特征用于下游任务

python 复制代码
# 将UMAP作为特征提取器
umap_featurizer = umap.UMAP(n_components=50, random_state=42)
X_umap_features = umap_featurizer.fit_transform(X_train)

# 现在X_umap_features可以替换X_train用于任何分类器
clf = RandomForestClassifier()
clf.fit(X_umap_features, y_train)

这种"UMAP + 分类器"的两步法在单细胞RNA测序数据分析中尤为常见。

八、UMAP降维后效果评估

评估方法

方法 说明
可视化检查 观察簇是否分离、是否有意义
k-近邻保留率 检查原始空间中的邻居在嵌入空间中是否仍是邻居
下游任务性能 用降维后的数据训练模型,比较准确率
轮廓系数 评估聚类分离程度

何时UMAP效果最佳

推荐使用UMAP的场景

  • 单细胞RNA测序数据(非线性、高噪声)
  • 图像数据(像素间存在复杂非线性关系)
  • 探索性数据分析,需发现非线性结构
  • 样本量较大(>5000),t-SNE速度太慢

推荐使用PCA的场景

  • 需要特征解释性(理解每个主成分的含义)
  • 数据确实接近线性结构(如某些物理测量)
  • 降维后需要重构原始数据
  • 作为线性模型的预处理步骤

准确性可能降低的原因

原因 说明
随机性 UMAP的随机初始化可能导致次优嵌入,需设置random_state
参数不当 n_neighbors过小导致局部过拟合,过大则模糊簇边界
维度选择过低 强行压入2维可能丢失信息
数据不适合流形学习 如果数据完全随机分布、不构成低维流形结构,UMAP会失效

九、3D UMAP可视化

对于更精细的可视化需求,UMAP支持将数据降到3维,配合交互式绘图库(如plotly)可以获得更好的探索体验。

python 复制代码
import plotly.express as px
import pandas as pd
from sklearn.datasets import make_classification
import umap

# 1. 构造高维分类数据集(300维,1000个样本)
X, y = make_classification(
    n_samples=1000, n_features=300,
    n_informative=250, n_classes=2, random_state=42
)


# 1. 降维到3维
reducer_3d = umap.UMAP(n_components=3, n_neighbors=15, random_state=42)
X_umap_3d = reducer_3d.fit_transform(X)

# 2. 构建DataFrame用于绘图
df_plot = pd.DataFrame({
    'UMAP1': X_umap_3d[:, 0],
    'UMAP2': X_umap_3d[:, 1],
    'UMAP3': X_umap_3d[:, 2],
    'Label': y  # 将标签转换为字符串以便显示
})

# 3. 生成交互式3D图
fig = px.scatter_3d(
    df_plot, x='UMAP1', y='UMAP2', z='UMAP3',
    color='Label',
    opacity=0.7,
    title='3D UMAP Visualization'
)

fig.update_traces(marker=dict(size=2))
fig.show()


这种方式会生成的HTML文件支持鼠标拖拽旋转、缩放。

十、技巧:预计算k-近邻加速

对于需要多次尝试不同n_neighborsmin_dist参数的场景,可以预计算k-近邻图以避免重复计算:

python 复制代码
from sklearn.datasets import make_classification
import umap
from umap.umap_ import nearest_neighbors

# 生成示例数据
X, y = make_classification(
    n_samples=2000,
    n_features=50,
    n_informative=40,
    random_state=42
)

print(f"原始数据形状: {X.shape}")

max_neighbors = 250

# 计算 k-近邻(返回索引和距离)
knn_indices, knn_dists, knn_search_params = nearest_neighbors(
    X=X,
    n_neighbors=max_neighbors,
    metric='euclidean',
    metric_kwds=None,
    angular=False,
    random_state=42,
    verbose=False
)

# 使用预计算的 k-近邻图进行 UMAP 降维
umap_model = umap.UMAP(
    n_neighbors=50,
    n_components=2,
    min_dist=0.1,
    random_state=42,
    precomputed_knn=(knn_indices, knn_dists)  
)

X_umap = umap_model.fit_transform(X)
print(f"降维后形状: {X_umap.shape}")

这种方法可以减少重复计算 k-近邻图的开销,尤其当需要多次调整 n_neighbors 参数时。

十一、结论

UMAP是目前最强大的非线性降维工具之一,在可视化质量和计算效率之间达到了优秀的平衡。

对比维度 PCA UMAP
适合数据类型 线性 非线性流形
可解释性 高(主成分载荷)
可视化质量 一般 优秀
计算效率 非常快 快(比t-SNE快)
随机性 有(设种子可重复)

选择建议

  • 做数据探索/可视化 :UMAP(尤其单细胞、图像、文本嵌入)
  • 做标准化的特征工程 :PCA(更快、可解释、无随机性)
  • 用完整流水线 :两者都可集成,用交叉验证对比

UMAP使用最佳实践

  1. 始终设置random_state以确保结果可重复
  2. n_neighbors=15开始,根据可视化效果和下游任务调整
  3. 对于可视化,优先用2维;对于特征提取,用交叉验证选择n_components
  4. 大规模数据(>10万)建议使用预计算k-近邻加速
  5. 如果簇边界模糊,尝试增大min_dist降低点之间的挤压

十二、 相关文章

PCA降维介绍

相关推荐
一粒马豆2 个月前
如何在二维平面内同时体现系列词汇的词频和相关性?
python·平面·数据可视化·词嵌入·降维·chromadb
weisian1513 个月前
进阶篇-8-数学篇-7--特征值与特征向量:AI特征提取的核心逻辑
人工智能·pca·特征值·特征向量·降维
dulu~dulu4 个月前
机器学习题目总结(二)
人工智能·机器学习·支持向量机·聚类·集成学习·降维·贝叶斯分类器
Aspect of twilight5 个月前
三种降维方式(PCA,t-SNE,UMAP)详解
深度学习·降维
民乐团扒谱机7 个月前
PCA 主成分分析:数据世界的 “旅行清单整理师”—— 从 30 维杂乱到 2 维清晰的诗意降维
大数据·数学建模·matlab·pca·主成分分析·数据处理·降维
AI 嗯啦9 个月前
机械学习---- PCA 降维深度解析
人工智能·pca·降维
PeterClerk1 年前
机器学习-无监督学习总结
人工智能·机器学习·聚类·生成模型·无监督学习·降维
martian6651 年前
【人工智能机器学习基础篇】——深入详解无监督学习之降维:PCA与t-SNE的关键概念与核心原理
人工智能·机器学习·无监督学习·降维
CM莫问2 年前
什么是降维?
人工智能·python·算法·机器学习·降维