关于 umap-learn
UMAP-Learn 是用于非线性降维的 Python 库,供数据科学和机器学习工作中进行可视化与预处理。它支持监督式嵌入、新数据转换、保留密度的 DensMAP,以及用于对齐数据集和神经网络嵌入的变体。
主要功能
- 01非线性降维
- 02监督式与半监督式嵌入
- 03将新数据映射到已拟合空间
- 04保留密度的 DensMAP
- 05对齐多个数据集的嵌入
- 06基于神经网络的 Parametric UMAP
适用场景
- 01将高维数据投影到 2D 或 3D
- 02为基于密度的聚类准备嵌入
- 03为机器学习工作流构造特征
- 04比较不同时间点或批次的嵌入
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ jaechang-hits/ sciagent-skills --skill umap-learn安装后在 Claude Code 中输入/umap-learn确认已加载。
附带文件references/api_reference.md
详细介绍
UMAP-Learn
概述
UMAP(统一流形逼近与投影)是一种用于可视化和通用非线性降维的降维算法。它比 t-SNE 更快,可扩展到更大的数据集,同时保留局部和全局结构,并支持监督学习以及新数据点的嵌入。
适用场景
- 将高维数据降至 2D/3D,以便可视化
- 用于基于密度的聚类(HDBSCAN、DBSCAN)的预处理
- 在 ML 工作流中进行特征工程(将新数据转换为已学习的嵌入)
- 使用部分标签进行监督式/半监督式嵌入
- 跟踪不同时间点或批次间的嵌入(AlignedUMAP)
- 保持密度的嵌入(DensMAP)
- 使用自定义架构进行基于神经网络的嵌入(Parametric UMAP)
- 线性降维请使用 PCA(scikit-learn)
- 不进行嵌入、仅构建邻域图时,请使用 scikit-learn NearestNeighbors
前置条件
pip install umap-learn
# For Parametric UMAP (neural network variant)
pip install umap-learn[parametric_umap] # requires TensorFlow 2.x
重要:应用 UMAP 前务必对特征进行标准化,以确保各维度的权重相同。
快速入门
import umap
import numpy as np
from sklearn.preprocessing import StandardScaler
from sklearn.datasets import load_digits
# Load and scale data
X, y = load_digits(return_X_y=True)
X_scaled = StandardScaler().fit_transform(X)
# Fit and transform
embedding = umap.UMAP(random_state=42).fit_transform(X_scaled)
print(f"Input: {X_scaled.shape}, Output: {embedding.shape}")
# Input: (1797, 64), Output: (1797, 2)
核心 API
1. 标准 UMAP
遵循 scikit-learn 约定的基础降维。
import umap
from sklearn.preprocessing import StandardScaler
X_scaled = StandardScaler().fit_transform(data)
# Method 1: fit_transform (single step)
embedding = umap.UMAP(
n_neighbors=15, # local neighborhood size (2-200)
min_dist=0.1, # min distance between embedded points (0.0-0.99)
n_components=2, # output dimensions
metric='euclidean', # distance metric
random_state=42, # reproducibility
).fit_transform(X_scaled)
print(f"Embedding shape: {embedding.shape}")
# Method 2: fit + access (for reuse)
reducer = umap.UMAP(random_state=42)
reducer.fit(X_scaled)
embedding = reducer.embedding_ # trained embedding
graph = reducer.graph_ # fuzzy simplicial set (sparse matrix)
# Visualization
import matplotlib.pyplot as plt
plt.figure(figsize=(8, 6))
plt.scatter(embedding[:, 0], embedding[:, 1], c=labels, cmap='Spectral', s=5)
plt.colorbar()
plt.title('UMAP Embedding')
plt.tight_layout()
plt.savefig('umap_embedding.png', dpi=150)
2. 监督式与半监督式 UMAP
通过 y 参数纳入标签信息,以引导嵌入。
import umap
# Supervised — all labels known
embedding = umap.UMAP(random_state=42).fit_transform(X_scaled, y=labels)
# Semi-supervised — partial labels (mark unlabeled as -1)
semi_labels = labels.copy()
semi_labels[unlabeled_indices] = -1
embedding = umap.UMAP(random_state=42).fit_transform(X_scaled, y=semi_labels)
# Control label influence with target_weight (0.0=unsupervised, 1.0=fully supervised)
reducer = umap.UMAP(
target_weight=0.7, # emphasize labels
target_metric='categorical', # for classification; use distance metric for regression
random_state=42
)
embedding = reducer.fit_transform(X_scaled, y=labels)
print(f"Supervised embedding: {embedding.shape}")
3. 转换新数据
将未见过的数据投影到训练得到的嵌入空间中。
import umap
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)
# Fit on training data
reducer = umap.UMAP(n_components=10, random_state=42)
X_train_emb = reducer.fit_transform(X_train_scaled)
# Transform test data
X_test_emb = reducer.transform(X_test_scaled)
print(f"Train: {X_train_emb.shape}, Test: {X_test_emb.shape}")
# Works in sklearn Pipelines
from sklearn.pipeline import Pipeline
from sklearn.svm import SVC
pipeline = Pipeline([
('scaler', StandardScaler()),
('umap', umap.UMAP(n_components=10, random_state=42)),
('classifier', SVC())
])
pipeline.fit(X_train, y_train)
accuracy = pipeline.score(X_test, y_test)
print(f"Pipeline accuracy: {accuracy:.3f}")
4. Parametric UMAP
通过 TensorFlow/Keras 实现基于神经网络的嵌入。支持高效转换、重构和自定义架构。
from umap.parametric_umap import ParametricUMAP
# Default architecture (3-layer, 100-neuron FC network)
embedder = ParametricUMAP(n_components=2, random_state=42)
embedding = embedder.fit_transform(X_scaled)
new_emb = embedder.transform(new_data) # fast neural network inference
print(f"Parametric embedding: {embedding.shape}")
import tensorflow as tf
from umap.parametric_umap import ParametricUMAP
# Custom encoder/decoder for autoencoder mode
input_dim = X_scaled.shape[1]
encoder = tf.keras.Sequential([
tf.keras.layers.InputLayer(input_shape=(input_dim,)),
tf.keras.layers.Dense(128, activation='relu'),
tf.keras.layers.Dense(64, activation='relu'),
tf.keras.layers.Dense(2),
])
decoder = tf.keras.Sequential([
tf.keras.layers.InputLayer(input_shape=(2,)),
tf.keras.layers.Dense(64, activation='relu'),
tf.keras.layers.Dense(128, activation='relu'),
tf.keras.layers.Dense(input_dim),
])
embedder = ParametricUMAP(
encoder=encoder, decoder=decoder, dims=(input_dim,),
parametric_reconstruction=True, autoencoder_loss=True,
n_training_epochs=10, batch_size=128,
n_neighbors=15, min_dist=0.1, random_state=42
)
embedding = embedder.fit_transform(X_scaled)
reconstructed = embedder.inverse_transform(embedding)
print(f"Reconstruction error: {np.mean((X_scaled - reconstructed)**2):.4f}")
5. DensMAP
一种在嵌入中保留局部密度信息的变体。
import umap
reducer = umap.UMAP(
densmap=True, # enable DensMAP
dens_lambda=2.0, # density preservation weight
dens_frac=0.3, # fraction for density estimation
output_dens=True, # output density estimates
n_neighbors=15,
min_dist=0.1,
random_state=42
)
embedding = reducer.fit_transform(X_scaled)
# Access density estimates
original_density = reducer.rad_orig_ # density in original space
embedded_density = reducer.rad_emb_ # density in embedded space
print(f"DensMAP embedding: {embedding.shape}")
print(f"Density correlation: {np.corrcoef(original_density, embedded_density)[0,1]:.3f}")
6. AlignedUMAP
对齐多个相关数据集(时间点、批次)之间的嵌入。
from umap import AlignedUMAP
# Multiple related datasets
datasets = [day1_data, day2_data, day3_data]
mapper = AlignedUMAP(
n_neighbors=15,
alignment_regularisation=1e-2, # alignment strength
alignment_window_size=2, # align with N adjacent datasets
n_components=2,
random_state=42
)
mapper.fit(datasets)
aligned_embeddings = mapper.embeddings_ # list of aligned embedding arrays
print(f"Aligned {len(aligned_embeddings)} datasets")
for i, emb in enumerate(aligned_embeddings):
print(f" Dataset {i}: {emb.shape}")
核心概念
参数调优指南
| 参数 | 低 | 中(默认) | 高 | 效果 |
|---|---|---|---|---|
n_neighbors | 2-5 | 15 | 50-200 | 局部细节与全局结构之间的权衡 |
min_dist | 0.0 | 0.1 | 0.5-0.99 | 紧密聚类与分散分布之间的权衡 |
n_components | 2 | 2 | 5-50 | 可视化与 ML/聚类之间的权衡 |
spread | 0.5 | 1.0 | 2.0 | 嵌入尺度(与 min_dist 配合) |
按使用场景配置
| 使用场景 | n_neighbors | min_dist | n_components | metric |
|---|---|---|---|---|
| 可视化 | 15 | 0.1 | 2 | euclidean |
| 聚类(HDBSCAN) | 30 | 0.0 | 5-10 | euclidean |
| 文本/文档嵌入 | 15 | 0.1 | 2 | cosine |
| 全局结构 | 100 | 0.5 | 2 | euclidean |
| ML 特征工程 | 15-30 | 0.1 | 10-50 | euclidean |
| 二元/集合数据 | 15 | 0.1 | 2 | hamming/jaccard |
支持的度量
闵可夫斯基族:euclidean、manhattan、chebyshev、minkowski。空间度量:canberra、braycurtis、haversine。相关性度量:cosine、correlation。二元度量:hamming、jaccard、dice、russellrao、rogerstanimoto、sokalmichener、sokalsneath、yule。特殊选项:precomputed(距离矩阵)、自定义的 Numba 编译可调用对象。
标准 UMAP 与 Parametric UMAP 对比
| 特性 | 标准版 | 参数化版 |
|---|---|---|
| 后端 | 直接优化 | TensorFlow 神经网络 |
| 转换速度 | 中等 | 快(神经网络推理) |
| 逆变换 | 近似,耗时 | 解码器网络,速度快 |
| 自定义架构 | 否 | 是(CNN、RNN 等) |
| 依赖要求 | umap-learn | umap-learn + TensorFlow 2.x |
| 适用场景 | 快速探索 | 生产工作流、重构 |
常见工作流
工作流 1:UMAP + HDBSCAN 聚类流程
import umap
import hdbscan
import numpy as np
import matplotlib.pyplot as plt
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import adjusted_rand_score
# Step 1: Preprocess
X_scaled = StandardScaler().fit_transform(data)
print(f"Input shape: {X_scaled.shape}")
# Step 2: UMAP for clustering (NOT visualization parameters)
reducer = umap.UMAP(
n_neighbors=30, # more global structure for clustering
min_dist=0.0, # allow tight packing
n_components=10, # higher dims preserve density better than 2D
metric='euclidean',
random_state=42
)
embedding = reducer.fit_transform(X_scaled)
# Step 3: HDBSCAN clustering
clusterer = hdbscan.HDBSCAN(min_cluster_size=15, min_samples=5)
cluster_labels = clusterer.fit_predict(embedding)
n_clusters = len(set(cluster_labels)) - (1 if -1 in cluster_labels else 0)
noise = sum(cluster_labels == -1)
print(f"Clusters: {n_clusters}, Noise: {noise}")
# Step 4: Separate 2D embedding for visualization
vis_emb = umap.UMAP(n_neighbors=15, min_dist=0.1, random_state=42).fit_transform(X_scaled)
plt.scatter(vis_emb[:, 0], vis_emb[:, 1], c=cluster_labels, cmap='Spectral', s=5)
plt.colorbar()
plt.title(f'HDBSCAN Clusters (n={n_clusters})')
plt.tight_layout()
plt.savefig('umap_clusters.png', dpi=150)
工作流 2:用于分类的监督式嵌入
import umap
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.svm import SVC
from sklearn.metrics import classification_report
# Split and scale
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
scaler = StandardScaler()
X_train_s = scaler.fit_transform(X_train)
X_test_s = scaler.transform(X_test)
# Supervised UMAP for feature engineering
reducer = umap.UMAP(n_components=10, random_state=42)
X_train_emb = reducer.fit_transform(X_train_s, y=y_train)
X_test_emb = reducer.transform(X_test_s)
# Downstream classifier
clf = SVC(kernel='rbf')
clf.fit(X_train_emb, y_train)
y_pred = clf.predict(X_test_emb)
print(classification_report(y_test, y_pred))
工作流 3:通过逆变换探索嵌入空间
仅限文本——组合核心 API 模块 1 和 3(对标准 UMAP 使用 inverse_transform):
- 在数据上拟合标准 UMAP(核心 API:标准 UMAP)
- 创建覆盖整个嵌入空间的网格点
- 应用
reducer.inverse_transform(grid_points)重建高维数据 - 可视化重建的样本,以了解嵌入区域
注意:逆变换是近似的;在训练嵌入的凸包之外效果较差。
关键参数
| 参数 | 模块 | 默认值 | 范围 | 效果 |
|---|---|---|---|---|
n_neighbors | UMAP | 15 | 2-200 | 局部与全局结构的平衡 |
min_dist | UMAP | 0.1 | 0.0-0.99 | 簇的紧密程度 |
n_components | UMAP | 2 | 2-100 | 输出维度 |
metric | UMAP | 'euclidean' | 参见指标列表 | 距离计算方法 |
spread | UMAP | 1.0 | >0 | 嵌入尺度(与 min_dist 配合使用) |
n_epochs | UMAP | None (自动) | 50-500+ | 训练迭代次数 |
learning_rate | UMAP | 1.0 | >0 | SGD 步长 |
init | UMAP | 'spectral' | spectral/random/pca | 嵌入初始化方式 |
random_state | UMAP | None | int | 可复现性随机种子 |
target_weight | UMAP | 0.5 | 0.0-1.0 | 标签影响程度(监督式) |
densmap | UMAP | False | bool | 启用 DensMAP |
dens_lambda | UMAP | 2.0 | >0 | DensMAP 密度权重 |
low_memory | UMAP | True | bool | 节省内存模式 |
encoder | ParametricUMAP | None | Keras 模型 | 自定义编码器网络 |
decoder | ParametricUMAP | None | Keras 模型 | 自定义解码器网络 |
n_training_epochs | ParametricUMAP | 1 | 1-100 | 神经网络训练轮数 |
alignment_regularisation | AlignedUMAP | 0.01 | >0 | 对齐强度 |
alignment_window_size | AlignedUMAP | 3 | 1-N | 要对齐的相邻数据集数量 |
最佳实践
-
始终标准化特征:在 UMAP 前使用
StandardScaler——范围不同且未缩放的特征会主导嵌入结果。 -
设置
random_state以确保可复现性:UMAP 使用随机优化;如果不固定随机种子,每次运行的结果都会不同。 -
针对聚类和可视化使用不同参数:聚类需要
n_neighbors=30, min_dist=0.0, n_components=5-10。可视化需要n_neighbors=15, min_dist=0.1, n_components=2。 -
反模式——按字面意义解读距离:UMAP 保留的是拓扑结构,而非精确距离。嵌入中的簇间隔和点间距离与原始距离并不成正比。
-
反模式——使用 2D 嵌入进行聚类:2D 投影会丢失密度信息。为 HDBSCAN 输入使用 5-10 个分量。
-
对于超高维数据,考虑先进行 PCA 预处理:对于特征数超过 1000 的数据,先降至 50-100 个 PCA 分量,可在不损失质量的情况下加快 UMAP 运行速度。
-
在生产环境中使用 Parametric UMAP:如果需要快速转换新数据或具备重建能力,Parametric UMAP 的神经网络可提供稳定、快速的推理。
常用方案
方案:自定义 Numba 距离指标
from numba import njit
import umap
@njit()
def weighted_euclidean(x, y):
"""Custom distance with feature weights."""
result = 0.0
for i in range(x.shape[0]):
result += (x[i] - y[i]) ** 2 * (1.0 + i * 0.01) # increasing weight
return np.sqrt(result)
embedding = umap.UMAP(metric=weighted_euclidean, random_state=42).fit_transform(data)
方案:预计算距离矩阵
import umap
from scipy.spatial.distance import pdist, squareform
# Compute custom distance matrix
dist_matrix = squareform(pdist(data, metric='correlation'))
# Use precomputed distances
embedding = umap.UMAP(
metric='precomputed', random_state=42
).fit_transform(dist_matrix)
print(f"Embedding from precomputed: {embedding.shape}")
方案:度量学习流水线
import umap
from sklearn.svm import SVC
# Train supervised embedding on labeled data
mapper = umap.UMAP(n_components=10, random_state=42)
train_emb = mapper.fit_transform(X_train, y=y_train)
# Transform unlabeled test data using learned metric
test_emb = mapper.transform(X_test)
# Downstream classifier
clf = SVC().fit(train_emb, y_train)
predictions = clf.predict(test_emb)
print(f"Accuracy: {(predictions == y_test).mean():.3f}")
故障排查
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 簇断开或碎片化 | n_neighbors 过低 | 增大 n_neighbors(尝试 30-50) |
| 簇过于分散 | min_dist 过高 | 减小 min_dist(尝试 0.0-0.05) |
| 所有点都挤在一起 | 预处理不当或 min_dist 过低 | 检查 StandardScaler;增大 min_dist |
| 聚类效果不佳 | 使用了可视化参数进行聚类 | 设置 n_neighbors=30, min_dist=0.0, n_components=5-10 |
| 转换结果与训练结果不同 | 分布偏移 | 确保测试数据与训练数据的分布一致;使用 Parametric UMAP |
| 大型数据集(>100k)运行缓慢 | 默认设置 | 设置 low_memory=True;先用 PCA 将数据预处理为 50-100 维 |
| 首次运行非常缓慢 | Numba JIT 编译 | 这是预期现象——后续运行会很快(已编译并缓存) |
ImportError: umap | 与 umap 包名称冲突 | pip install umap-learn(而非 pip install umap) |
| Parametric UMAP 导入错误 | 缺少 TensorFlow | pip install umap-learn[parametric_umap] |
| 结果不可复现 | 未设置 random_state | 始终设置 random_state=42(或任意整数) |
捆绑资源
references/api_reference.md
完整的 UMAP 构造函数参数参考(60 多个参数,按类别组织:核心、训练、高级结构、监督式、转换、性能、DensMAP)、所有方法和属性、带有自动编码器参数的 ParametricUMAP 类、AlignedUMAP 类、实用函数(nearest_neighbors、fuzzy_simplicial_set)。核心参数调优指南已移至 SKILL.md 的 Key Concepts 和 Core API 模块。省略了与 SKILL.md 工作流重复的用法示例。
相关技能
- scikit-learn-machine-learning — 用于下游任务的 ML 分类器、预处理和流水线
- matplotlib-scientific-plotting — UMAP 嵌入的可视化
- scikit-bio — 可通过
metric='precomputed'输入 UMAP 的生物学距离矩阵
参考资料
- McInnes L、Healy J、Melville J。《UMAP:用于降维的统一流形近似与投影》。arXiv:1802.03426
- Sainburg T、McInnes L、Gentner TQ。《用于表征与半监督学习的参数化 UMAP 嵌入》。Neural Computation(2021)
- Narayan A、Berger B、Cho H。《通过保留密度的数据可视化评估单细胞转录组变异性》。Nature Biotechnology(2021)——DensMAP
- 官方文档:https://umap-learn.readthedocs.io/
- GitHub:https://github.com/lmcinnes/umap