1004.特征工程-特征降维-UMAP

均匀流形逼近与投影(Uniform Manifold Approximation and Projection,UMAP)由 McInnes 等(2018)提出,是基于流形学习拓扑数据分析的非线性降维方法。它将高维数据映射到 2D/3D,在保留局部簇结构的同时,通常比 t-SNE 更快、更好地保留全局拓扑

段末注释UMAPt-SNE 一样,主用途是可视化与探索;低维坐标不宜直接当作监督学习特征。

读前说明:配图位于同名目录 1004.特征工程-特征降维-UMAP/;正文图链写 ./1004.特征工程-特征降维-UMAP/文件名。系列索引:降维概述 | PCA | t-SNE


1. 产生基础:为什么需要 UMAP

1.1 问题来源

t-SNE 在 2010 年代成为高维数据可视化标配,但存在明显痛点:

  1. 速度慢:$N > 10^4$ 时计算昂贵;
  2. 全局结构差:簇间距离、连续轨迹(如发育过程)常被扭曲;
  3. 超参敏感:perplexity 变化可导致图形大幅改变。

UMAP 的出发点:在流形假设下,用更高效的图拓扑对齐框架,同时保留局部邻域部分全局相对位置

1.2 核心假设

高维观测 $\mathbf{x}_i \in \mathbb{R}^D$ 实际来自某个低维流形 $\mathcal{M}$ 的嵌入:

$$
\mathbf{x}_i = f(\mathbf{z}_i) + \epsilon,\quad \mathbf{z}_i \in \mathcal{M},; \dim(\mathcal{M}) \ll D
$$

UMAP 不直接估计 $f$,而是保留流形上的邻域关系(谁与谁相近)。


2. 演进脉络

图 1 UMAP 演进脉络(科普示意)

阶段 代表方法 与 UMAP 关系
~1960s MDS(多维缩放) 保留成对距离;全局但线性/度量约束
~2000 LLEISOMAP 局部流形学习先驱
2008 t-SNE 局部概率对齐;UMAP 的重要对照基线
2018 UMAP McInnes, Healy, Melville;广义熵 + 模糊拓扑
2019+ ScanpySeurat 单细胞分析默认降维之一
2023+ ESM Atlas 百万级蛋白结构 UMAP 探索

段末注释MDS 通过保持距离矩阵降维;LLE(局部线性嵌入)假设每个点可由其近邻线性表示。


3. 算法原理

图 2 UMAP 算法原理(科普示意)

3.1 两步总览

1
2
3
4
5
高维空间 X
→ 步骤1:建 k 近邻图,构造模糊单纯集(边权 = 局部相似度)→ 高维图 P
→ 步骤2:初始化低维 Y,构造低维图 Q
→ 最小化交叉熵 CE(P, Q),迭代优化 Y
低维坐标 Y

直观理解:该连的边在低维仍连,不该连的仍断开

3.2 高维:模糊拓扑

对每个点 $i$,找 n_neighbors 个近邻,定义局部连通强度;经归一化得到高维边权 $p_{ij}$。远距离边权重趋近 0(稀疏图)。

与 t-SNE 高斯核类似,但 UMAP 采用模糊单纯集(fuzzy simplicial set)框架,便于与拓扑数据分析衔接。

3.3 低维:交叉熵对齐

低维坐标 $\mathbf{y}i$ 上定义边权 $q{ij}$,最小化:

$$
\mathrm{CE}(P, Q) = \sum_{ij} \left[ p_{ij} \log \frac{p_{ij}}{q_{ij}} + (1-p_{ij}) \log \frac{1-p_{ij}}{1-q_{ij}} \right]
$$

优化 $\mathbf{y}_i$ 使低维图拓扑逼近高维图。

3.4 与 t-SNE 的数学差异

维度 t-SNE UMAP
高维相似度 高斯 + perplexity 模糊拓扑 + n_neighbors
低维分布 t 分布 可配置(默认类似 t 族)
损失函数 $\mathrm{KL}(P|Q)$ 交叉熵 $\mathrm{CE}(P,Q)$
扩展性 Barnes-Hut 后 $O(N\log N)$ 近似近邻,百万级可行
全局结构 相对较好

3.5 关键超参的拓扑含义

  • n_neighbors:小 → 强调局部细节;大 → 更偏全局结构(类似 t-SNE 的 perplexity)。
  • min_dist:低维点允许的最小间距;小 → 簇更;大 → 点更分散

4. 适用场景

图 3 UMAP 适用场景(科普示意)

场景 为什么选 UMAP 示例
大规模单细胞图谱 速度快,可处理 $10^5$+ 细胞 Scanpy sc.tl.umap
蛋白结构/序列宇宙 保留簇间拓扑,便于浏览 ESM Atlas 2D 地图
酶变体嵌入探索 蛋白工程表征初筛首选 酶改造-06 §6.2
连续轨迹/发育过程 比 t-SNE 更好保留全局连续结构 拟时序分析辅助可视化
与 t-SNE 对照 需要紧簇边界时并用 t-SNE 双图验证结论稳健性

不适用

  • 需要线性可解释主成分(用 PCA);
  • 需要稳定特征输入回归器(用原始嵌入);
  • 样本极少($N < 20$)且需精确定量(图噪声过大)。

5. 局限性

图 4 UMAP 局限性(科普示意)

局限 说明 应对
超参仍影响结果 n_neighbors、min_dist 改变簇形态 记录参数;小范围网格搜索;与 t-SNE 对照
小样本噪声大 $N < 30$ 时拓扑不稳定 结论保守;优先增加实验数据
不宜作训练特征 低维坐标语义随 fit 变化 用原始高维嵌入或 PCA
fit 泄漏风险 全量 fit_transform 见过所有标签信息 探索性可视化可全量 fit;严格评估时仅 train fit + test transform
非唯一解 随机初始化 + 非凸优化 固定 random_state;多次运行取共识

6. 主要超参数

参数 含义 建议
n_neighbors 局部邻域大小 默认 15;小文库($N<50$)试 5~10
min_dist 低维最小点间距 0.0~0.5;默认 0.1
metric 距离度量 高维嵌入常用 'euclidean'
n_components 输出维度 可视化 23
random_state 随机种子 固定以便复现

7. 示例展示与代码

安装:pip install umap-learn

7.1 合成数据演示(可直接运行)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
"""UMAP 合成示例:digits 数据集,与 t-SNE 对照"""
import matplotlib.pyplot as plt
import numpy as np
import umap
from sklearn.datasets import load_digits
from sklearn.manifold import TSNE
from sklearn.preprocessing import StandardScaler

digits = load_digits()
X = StandardScaler().fit_transform(digits.data)
y = digits.target

# UMAP
Z_umap = umap.UMAP(n_neighbors=15, min_dist=0.1, random_state=42).fit_transform(X)

# t-SNE 对照
Z_tsne = TSNE(n_components=2, perplexity=30, init="pca", random_state=42).fit_transform(X)

fig, axes = plt.subplots(1, 2, figsize=(14, 5))
for ax, Z, title in zip(axes, [Z_umap, Z_tsne], ["UMAP", "t-SNE"]):
sc = ax.scatter(Z[:, 0], Z[:, 1], c=y, cmap="tab10", s=12, alpha=0.8)
ax.set_title(f"digits — {title}")
ax.set_xlabel("dim 1"); ax.set_ylabel("dim 2")
plt.colorbar(sc, ax=axes[1], label="digit")
plt.tight_layout()
plt.savefig("umap_vs_tsne_digits.png", dpi=150)

预期观察:两者均能将 0~9 分开;UMAP 往往簇间相对位置更有规律,t-SNE 簇边界有时更「紧」。

7.2 蛋白变体嵌入质控

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
"""蛋白变体 UMAP 质控 + 超参扫描"""
import numpy as np
import umap
import matplotlib.pyplot as plt

X = np.load("embeddings.npy") # (N, D)
y = np.load("labels.npy") # log10(activity/WT)

n_neighbors = min(15, max(5, X.shape[0] // 5))

reducer = umap.UMAP(
n_neighbors=n_neighbors,
min_dist=0.1,
n_components=2,
metric="euclidean",
random_state=42,
)
Z = reducer.fit_transform(X)

plt.figure(figsize=(7, 6))
plt.scatter(Z[:, 0], Z[:, 1], c=y, cmap="viridis", s=18, alpha=0.75)
plt.colorbar(label="log10(activity/WT)")
plt.xlabel("UMAP 1"); plt.ylabel("UMAP 2")
plt.title(f"Protein variants (n_neighbors={n_neighbors})")
plt.savefig("umap_protein_qc.png", dpi=150)

7.3 n_neighbors 敏感性对照

1
2
3
4
5
6
7
"""n_neighbors 对簇结构的影响"""
fig, axes = plt.subplots(1, 3, figsize=(15, 4))
for ax, k in zip(axes, [5, 15, 50]):
Z = umap.UMAP(n_neighbors=k, min_dist=0.1, random_state=42).fit_transform(X)
ax.scatter(Z[:, 0], Z[:, 1], c=y, cmap="viridis", s=10, alpha=0.7)
ax.set_title(f"n_neighbors={k}")
plt.savefig("umap_neighbors_sweep.png", dpi=150)

7.4 避免 fit 泄漏的写法(建模流水线)

1
2
3
4
5
6
7
8
"""训练集 fit,测试集 transform — 用于严格评估场景"""
from sklearn.model_selection import train_test_split

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

reducer = umap.UMAP(n_neighbors=15, random_state=42)
Z_train = reducer.fit_transform(X_train)
Z_test = reducer.transform(X_test) # 仅探索性可视化;仍不建议将 Z 喂给回归器

8. UMAP vs t-SNE 速查

维度 UMAP t-SNE
速度 通常更快,百万级可行 大数据需采样/PCA 预处理
全局结构 较好 不可靠
稳定性 对默认超参相对稳健 perplexity 敏感
transform 支持 transform 新样本 sklearn 需全量 fit_transform
生态 Scanpy、Seurat、umap-learn sklearn 内置

实践建议:蛋白变体嵌入探索优先 UMAP;强调紧簇边界时并用 t-SNE 对照。


9. 小结

  • UMAP 承继流形学习脉络,以模糊拓扑 + 交叉熵对齐高低维图结构。
  • 适合大规模可视化蛋白/单细胞探索保留部分全局拓扑的场景。
  • 与 t-SNE 相同,看图是初筛;定量评估仍需监督模型指标与实验验证。
  • 详见 酶改造-06t-SNE 专篇

参考文献

  1. McInnes L., Healy J., Melville J. UMAP: Uniform Manifold Approximation and Projection for Dimension Reduction. arXiv:1802.03426 2018.
  2. umap-learn 官方文档
  3. Becht E. et al. Dimensionality reduction for visualizing single-cell data using UMAP. Nat. Biotechnol. 2019, 37, 38–44.
  4. 特征降维算法比较综述
-------------本文结束感谢您的阅读-------------