AI 工程基础体系 · 第 50/100 篇。内容覆盖机器学习、深度学习与生成式 AI;模型、数据、评测、权限和成本会作为同一生产系统处理。

降维方法:PCA、SVD、t-SNE、UMAP 与可视化边界

降维(dimensionality reduction)是把高维数据映射到较低维空间的过程。设原始样本矩阵为

XRn×d,X\in\mathbb{R}^{n\times d},

其中 nn 是样本数,dd 是特征数。降维方法通常学习一个映射

f:RdRk,kd,f:\mathbb{R}^{d}\rightarrow\mathbb{R}^{k},\qquad k\ll d,

并得到低维表示

Z=f(X)Rn×k.Z=f(X)\in\mathbb{R}^{n\times k}.

这里的“保留信息”并不是绝对概念:PCA 主要保留方差,SVD 提供矩阵的低秩近似,t-SNE 强调局部邻域,UMAP 试图同时保留局部拓扑与部分全局结构。它们得到的坐标具有不同含义,因此不能把所有二维图都解释为“数据真实空间的缩小版”。

降维常见于四类任务:

  1. 压缩与去噪:用较少的数值近似原始特征;
  2. 下游建模:把低维表示输入分类、聚类或检索模型;
  3. 探索性分析:观察样本是否存在簇、异常点或连续结构;
  4. 可视化:将高维表示映射到二维或三维图中。

这些任务的目标不同。适合可视化的方法,不一定适合生产特征;在二维图上看起来分离的两个簇,也不一定能支持分类结论。


一、降维前必须先明确:要保留什么

“降维效果好”至少有三种不同含义。

1. 重构误差小

如果希望低维表示能够重构原始数据,目标可以写成:

minZ,WXZWF2,\min_{Z,W}\|X-ZW^\top\|_F^2,

其中:

  • ZRn×kZ\in\mathbb{R}^{n\times k} 是样本的低维坐标;
  • WRd×kW\in\mathbb{R}^{d\times k} 是从低维空间回到原空间的方向;
  • F\|\cdot\|_F 是 Frobenius 范数。

PCA 和截断 SVD 直接服务于这一类目标。

2. 下游任务性能高

如果降维后要做分类,可以比较:

score(y,y^(X))score(y,y^(Z)).\text{score}\bigl(y,\hat y(X)\bigr) \quad\text{与}\quad \text{score}\bigl(y,\hat y(Z)\bigr).

此时准确率、F1、AUC、召回率等任务指标比二维图是否“好看”更重要。

3. 局部邻域或拓扑关系保持

如果关心“哪些样本互相接近”,可以比较原空间和低维空间中的近邻集合。例如,对样本 ii,令 NkX(i)N_k^X(i)NkZ(i)N_k^Z(i) 分别表示两个空间中的 kk 近邻,则可以计算邻域保持率:

1ni=1nNkX(i)NkZ(i)k.\frac{1}{n}\sum_{i=1}^{n} \frac{|N_k^X(i)\cap N_k^Z(i)|}{k}.

t-SNE 和 UMAP 更接近这一目标,但它们的二维坐标通常不适合作为严格的距离测量工具。

因此,在选择算法之前,应先回答:是要近似原始矩阵、改善下游模型,还是帮助人观察结构?同一个数据集可能需要同时训练一个 PCA 特征管道和一个 t-SNE 可视化管道,但不能混用两者的解释方式。


二、PCA:寻找最大方差的线性子空间

2.1 PCA 的输入与中心化

PCA(Principal Component Analysis,主成分分析)寻找一组正交方向,使样本投影到这些方向后具有尽可能大的方差。

设原始矩阵为 XX。PCA 通常先按特征中心化:

Xc=X1μ,X_c=X-\mathbf{1}\mu^\top,

其中:

  • μRd\mu\in\mathbb{R}^d 是每个特征的均值;
  • 1Rn\mathbf{1}\in\mathbb{R}^{n} 是全 1 向量;
  • XcX_c 的每一列均值为 0。

如果各个特征的单位和尺度差异很大,常见做法是进一步标准化:

Xs=Xμσ,X_s=\frac{X-\mu}{\sigma},

其中 σ\sigma 是每个特征的标准差。此时 PCA 实际上作用于相关系数结构,而不是原始协方差结构。

是否标准化不能机械决定:

  • “年龄”和“收入”都是真实量纲,且收入的绝对波动本身有意义时,直接中心化可能合理;
  • “像素强度”和“计数特征”量纲差异很大时,标准化可能更合理;
  • 稀疏 TF-IDF 矩阵通常不直接使用会破坏稀疏性的标准化流程,而会考虑 TruncatedSVD。

2.2 方差最大化推导

先只寻找一个单位方向 wRdw\in\mathbb{R}^d,满足:

w2=1.\|w\|_2=1.

样本在该方向上的投影为:

z=Xcw.z=X_cw.

因为 XcX_c 已中心化,投影方差为:

Var(z)=1n1zz=1n1wXcXcw.\operatorname{Var}(z) =\frac{1}{n-1}z^\top z =\frac{1}{n-1}w^\top X_c^\top X_cw.

记样本协方差矩阵为:

S=1n1XcXc.S=\frac{1}{n-1}X_c^\top X_c.

于是 PCA 的第一主成分是如下优化问题的解:

maxw2=1wSw.\max_{\|w\|_2=1} w^\top Sw.

用拉格朗日乘子 λ\lambda

L(w,λ)=wSwλ(ww1).L(w,\lambda)=w^\top Sw-\lambda(w^\top w-1).

ww 求导并令其为零:

2Sw2λw=0,2Sw-2\lambda w=0,

因此:

Sw=λw.Sw=\lambda w.

也就是说,最优方向是协方差矩阵最大特征值对应的特征向量,最大方差等于该最大特征值。后续主成分还要满足互相正交,因此前 kk 个主成分由最大的 kk 个特征值对应的特征向量组成:

Wk=[w1,,wk],Z=XcWk.W_k=[w_1,\ldots,w_k], \qquad Z=X_cW_k.

2.3 PCA 的重构含义

低维坐标 ZZ 可以近似重构为:

X^=XcWkWk+μ.\hat X=X_cW_kW_k^\top+\mu.

其中 WkWkW_kW_k^\top 是投影到主成分子空间的矩阵。PCA 的一个重要性质是:在所有 kk 维线性子空间中,它使平方重构误差最小:

minrank(X^μ)kXX^F2.\min_{\operatorname{rank}(\hat X-\mu)\le k} \|X-\hat X\|_F^2.

因此,PCA 的“解释方差比”不是任意的可视化评分,而是:

explained_variance_ratioj=λjr=1dλr,\text{explained\_variance\_ratio}_j = \frac{\lambda_j}{\sum_{r=1}^{d}\lambda_r},

表示第 jj 个主成分解释的协方差总方差比例。

2.4 一个完整算例

考虑三个二维样本:

X=[112233].X= \begin{bmatrix} 1&1\\ 2&2\\ 3&3 \end{bmatrix}.

均值为:

μ=(2,2).\mu=(2,2).

中心化后:

Xc=[110011].X_c= \begin{bmatrix} -1&-1\\ 0&0\\ 1&1 \end{bmatrix}.

样本协方差矩阵为:

S=131XcXc=12[2222]=[1111].S=\frac{1}{3-1}X_c^\top X_c = \frac12 \begin{bmatrix} 2&2\\ 2&2 \end{bmatrix} = \begin{bmatrix} 1&1\\ 1&1 \end{bmatrix}.

它的两个特征值为 2200,对应单位特征向量可以取:

w1=12(1,1),w2=12(1,1).w_1=\frac{1}{\sqrt2}(1,1),\qquad w_2=\frac{1}{\sqrt2}(1,-1).

第一主成分坐标为:

Z1=Xcw1=[202].Z_1=X_cw_1= \begin{bmatrix} -\sqrt2\\ 0\\ \sqrt2 \end{bmatrix}.

第二主成分始终为 0,因为所有样本都落在直线 x1=x2x_1=x_2 上。这里 PCA 将二维数据无损地压缩成一维。

但这个结论依赖数据结构。如果把样本改为:

(0,10), (1,10), (2,10),(0,10),\ (1,10),\ (2,10),

第一主成分会沿着第一个特征方向,而不是沿着“数值较大的第二列”。PCA 关注的是中心化后的方差结构;如果先标准化,结果又可能改变,因为标准化改变了各维的相对尺度。

2.5 PCA 的边界

PCA 是线性的。对于圆环、月牙、S 曲线等非线性流形,数据可能在低维非线性结构上变化,但线性投影无法将其“拉直”。

例如,二维单位圆上的点满足:

x12+x22=1.x_1^2+x_2^2=1.

它本质上由一个角度参数决定,但圆的两个坐标方向方差都相近,PCA 不会发现一个能够无损表示圆环的“一维直线坐标”。把圆投影到任意一条直线都会折叠不同位置的点。

PCA 还存在以下边界:

  • 高方差不等于高预测价值。低方差特征可能包含少量但关键的标签信息;
  • 特征尺度会直接影响结果;
  • 主成分方向的符号没有意义,www-w 表示同一个子空间;
  • 当特征高度共线时,PCA 有效;当结构是强非线性时,PCA 可能严重不足;
  • PCA 会把输入中的敏感信息、身份信息和噪声一起编码,降维不等于匿名化。

三、SVD:PCA 的计算工具,也是更一般的低秩分解

3.1 SVD 的定义

任意实矩阵 ARn×dA\in\mathbb{R}^{n\times d} 都可以进行奇异值分解:

A=UΣV,A=U\Sigma V^\top,

其中:

  • URn×nU\in\mathbb{R}^{n\times n} 的列向量称为左奇异向量;
  • VRd×dV\in\mathbb{R}^{d\times d} 的列向量称为右奇异向量;
  • Σ\Sigma 是非负对角矩阵;
  • 奇异值满足 σ1σ20\sigma_1\ge\sigma_2\ge\cdots\ge0

如果只保留最大的 kk 个奇异值:

Ak=UkΣkVk,A_k=U_k\Sigma_kV_k^\top,

AkA_k 是 Frobenius 范数和谱范数意义下的最佳秩 kk 近似。这是 Eckart–Young 定理的核心结论。

截断 SVD 的平方重构误差为:

AAkF2=j>kσj2.\|A-A_k\|_F^2 = \sum_{j>k}\sigma_j^2.

3.2 SVD 与 PCA 的关系

对中心化矩阵做 SVD:

Xc=UΣV.X_c=U\Sigma V^\top.

则:

XcXc=VΣΣV.X_c^\top X_c = V\Sigma^\top\Sigma V^\top.

因此,协方差矩阵的特征向量就是 VV 的列向量,协方差特征值为:

λj=σj2n1.\lambda_j=\frac{\sigma_j^2}{n-1}.

PCA 的低维坐标为:

Z=XcVk=UkΣk.Z=X_cV_k=U_k\Sigma_k.

所以:

  • PCA 通常描述统计目标和主成分坐标;
  • SVD 是计算这种分解的线性代数工具;
  • 对中心化后的矩阵使用 SVD,可以得到 PCA;
  • 对未中心化矩阵做 SVD,不一定等同于 PCA。

3.3 为什么文本常用 TruncatedSVD

文本的 TF-IDF 矩阵通常具有以下特点:

  • nndd 都可能很大;
  • 矩阵高度稀疏;
  • 大量元素为 0;
  • 直接中心化会使矩阵变成稠密矩阵,带来严重的内存成本。

TruncatedSVD 直接在原稀疏矩阵上寻找低秩结构,常被用于潜在语义分析(LSA)。它不自动中心化,因此其结果不能不加说明地称为“标准 PCA”。

如果文本矩阵已经经过 TF-IDF,SVD 的方向可以捕获词项共现的低秩结构。低维坐标则可以用于相似度搜索、聚类或作为下游模型输入。但它并不理解词序、否定、语义组合,也不等价于现代语言模型的语义表示。

3.4 一个小型 SVD 算例

考虑已中心化矩阵:

A=[110011].A= \begin{bmatrix} -1&-1\\ 0&0\\ 1&1 \end{bmatrix}.

它是秩 1 矩阵。可以写成:

A=[12012]2[1212].A= \begin{bmatrix} -\frac1{\sqrt2}\\ 0\\ \frac1{\sqrt2} \end{bmatrix} \cdot 2 \cdot \begin{bmatrix} \frac1{\sqrt2}&\frac1{\sqrt2} \end{bmatrix}.

这里唯一非零奇异值为 22。因此保留一个奇异值即可完整重构 AA,与前面 PCA 得到一个有效主成分的结论一致。

3.5 随机化截断 SVD的工程含义

当矩阵很大且只需要前 kk 个方向时,常见实现会采用随机化算法近似求解前几个奇异向量。其优势是避免完整分解所有方向,通常减少时间和内存;代价是结果可能存在微小数值差异,并受随机种子、迭代次数和过采样参数影响。

这属于实现策略,不改变 SVD 的数学定义。生产中应记录:

  • 输入矩阵的构造方式;
  • 是否中心化或标准化;
  • kk
  • 随机种子;
  • 软件版本;
  • 拟合时使用的特征词表或列顺序。

四、PCA 与 SVD 的可运行对比

下面的例子使用 scikit-learn 的手写数字数据。每个样本是 8×88\times8 图像,展平后有 64 个像素特征。代码比较:

  • PCA:先标准化,再降到二维;
  • TruncatedSVD:直接对原始矩阵做截断 SVD;
  • t-SNE:直接生成二维可视化坐标。
import numpy as np
import matplotlib.pyplot as plt

from sklearn.datasets import load_digits
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA, TruncatedSVD
from sklearn.manifold import TSNE

# 1. 读取数据
digits = load_digits()
X = digits.data.astype(np.float64)
y = digits.target

# 为控制 t-SNE 计算成本,只抽取固定子集
X, _, y, _ = train_test_split(
    X, y,
    train_size=1200,
    stratify=y,
    random_state=42
)

# 2. PCA:标准化和降维必须只在训练数据上拟合
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

pca = PCA(n_components=2, random_state=42)
Z_pca = pca.fit_transform(X_scaled)

# 3. TruncatedSVD:这里不中心化
svd = TruncatedSVD(n_components=2, random_state=42)
Z_svd = svd.fit_transform(X)

# 4. t-SNE:它本身不是可逆压缩器
tsne = TSNE(
    n_components=2,
    perplexity=30,
    init="pca",
    learning_rate="auto",
    random_state=42,
    max_iter=1000,  # 某些旧版 sklearn 使用 n_iter
)
Z_tsne = tsne.fit_transform(X)

# 5. 可视化
fig, axes = plt.subplots(1, 3, figsize=(15, 4))

for ax, Z, title in [
    (axes[0], Z_pca, "PCA"),
    (axes[1], Z_svd, "TruncatedSVD"),
    (axes[2], Z_tsne, "t-SNE"),
]:
    scatter = ax.scatter(
        Z[:, 0], Z[:, 1],
        c=y,
        cmap="tab10",
        s=10,
        alpha=0.8
    )
    ax.set_title(title)
    ax.set_xlabel("component 1")
    ax.set_ylabel("component 2")

plt.tight_layout()
plt.show()

print("PCA explained variance ratio:",
      pca.explained_variance_ratio_)
print("TruncatedSVD explained variance ratio:",
      svd.explained_variance_ratio_)

前置条件是安装 numpymatplotlibscikit-learn。其中 TSNE 的迭代参数在不同 scikit-learn 版本中存在命名变化:较新的版本使用 max_iter,部分旧版本使用 n_iter,运行时报参数错误时应以当前安装版本的 API 文档为准,而不是盲目复制参数。

这个例子中:

  • PCA 的二维坐标具有线性投影含义,可以通过 inverse_transform 近似恢复图像;
  • TruncatedSVD 的二维坐标来自未中心化矩阵,不能直接等同于标准化 PCA;
  • t-SNE 的二维坐标主要用于观察局部邻域,不提供有意义的原空间重构;
  • 三幅图的坐标轴方向、尺度和符号不能直接相互比较。

如果 PCA 用于生产建模,正确的流程应把预处理和降维放入同一个 Pipeline,并只在训练集上拟合:

from sklearn.pipeline import Pipeline
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score

X_train, X_test, y_train, y_test = train_test_split(
    digits.data,
    digits.target,
    test_size=0.2,
    stratify=digits.target,
    random_state=42
)

pipeline = Pipeline([
    ("scaler", StandardScaler()),
    ("pca", PCA(n_components=0.95, random_state=42)),
    ("clf", LogisticRegression(max_iter=2000))
])

pipeline.fit(X_train, y_train)
pred = pipeline.predict(X_test)

print("test accuracy:", accuracy_score(y_test, pred))
print("retained dimensions:",
      pipeline.named_steps["pca"].n_components_)

这里 n_components=0.95 表示选择足够多的主成分,使累计解释方差达到约 95%。这只约束线性重构信息,不保证分类准确率一定最好,因此仍需和不降维的基线比较。


五、t-SNE:把高维邻域概率映射到低维

5.1 t-SNE 的目标不是最大化方差

t-SNE(t-distributed Stochastic Neighbor Embedding)首先把高维样本之间的邻近关系转化为概率。

对高维样本 xix_ixjx_j,以 xix_i 为中心定义条件概率:

pji=exp(xixj2/(2σi2))liexp(xixl2/(2σi2)),ji.p_{j|i} = \frac{ \exp\left(-\|x_i-x_j\|^2/(2\sigma_i^2)\right) }{ \sum_{l\ne i} \exp\left(-\|x_i-x_l\|^2/(2\sigma_i^2)\right) }, \qquad j\ne i.

其中 σi\sigma_i 是样本 ii 的局部带宽。不同样本可以有不同的 σi\sigma_i,以适应局部密度差异。

然后将条件概率对称化:

pij=pji+pij2n.p_{ij}=\frac{p_{j|i}+p_{i|j}}{2n}.

低维坐标为 yiy_i。t-SNE 使用自由度为 1 的 Student t 分布定义低维相似度:

qij=(1+yiyj2)1lr(1+ylyr2)1.q_{ij} = \frac{ (1+\|y_i-y_j\|^2)^{-1} }{ \sum_{l\ne r} (1+\|y_l-y_r\|^2)^{-1} }.

最后最小化两个分布之间的 KL 散度:

C=KL(PQ)=ijpijlogpijqij.C=\operatorname{KL}(P\|Q) =\sum_{i\ne j}p_{ij}\log\frac{p_{ij}}{q_{ij}}.

由于 KL 散度的方向是 PQP\|Q,如果原空间中的 pijp_{ij} 很大而低维空间中的 qijq_{ij} 很小,代价会很高;反过来,低维中出现额外的近邻,惩罚相对不同。这导致 t-SNE 更重视保留高维中的近邻,而不是均匀保持所有距离。

5.2 perplexity 的含义

perplexity 可以理解为每个点有效邻域大小的控制参数,数学上与条件概率熵有关:

Perp(Pi)=2H(Pi),\operatorname{Perp}(P_i)=2^{H(P_i)},

其中:

H(Pi)=jpjilog2pji.H(P_i)=-\sum_j p_{j|i}\log_2 p_{j|i}.

它不是“必须存在的簇数”,也不是严格的近邻数量。较小的 perplexity 更强调很局部的结构,较大的 perplexity 会考虑更宽的邻域。它必须与样本数、数据密度和目标结构一起解释;在不同取值下重复运行,是诊断稳定性的必要步骤。

5.3 为什么 t-SNE 常产生“漂亮的簇”

t-SNE 的低维空间使用重尾的 Student t 分布。相比高斯分布,重尾允许低维点在保持近邻的同时拉开更远距离,这缓解了“拥挤问题”。

但这也带来误解风险:

  • 不同簇之间的二维距离通常没有可靠的全局含义;
  • 簇的面积不代表簇大小;
  • 簇之间的空白区域不一定表示真实的低密度;
  • 簇的形状可能受初始化、学习率、早期夸大和随机优化影响;
  • t-SNE 会优先维护局部关系,可能把连续流形切成看似分离的岛。

因此,t-SNE 图中“两个簇相隔很远”只能较谨慎地解释为:算法在二维优化中将它们分开,以便保留各自的局部邻域。它不能直接证明原空间中存在同样大小、同样距离的两个自然类别。

5.4 早期夸大、初始化与随机性

t-SNE 的常见实现会在优化初期对高维相似度 PP 进行早期夸大,使局部簇暂时更明显,然后逐步恢复。这个过程有助于优化,但会影响视觉结果。

初始化方式也很重要:

  • init="random" 可能从随机位置开始;
  • init="pca" 通常提供更有结构的初始坐标;
  • random_state 可以使一次实验可复现,但不会使算法结果获得数学上的唯一性。

如果一张图只运行一次就下结论,无法区分数据结构和优化随机性。更可靠的诊断包括:

  1. 改变随机种子,观察局部邻域是否稳定;
  2. 改变 perplexity,观察簇是否持续存在;
  3. 在原空间计算 k 近邻指标;
  4. 用标签只做着色,不把标签输入拟合过程;
  5. 与 PCA 或 UMAP 的结果进行对照。

六、UMAP:基于邻域图与模糊拓扑结构的降维

6.1 UMAP 的基本思想

UMAP(Uniform Manifold Approximation and Projection)通常从以下假设出发:

  1. 数据近似位于某个低维流形上;
  2. 样本在流形上具有局部连通结构;
  3. 通过近邻关系可以近似恢复这一结构。

它不是简单地寻找一个线性投影,而是大致经过以下步骤:

  1. 为每个样本寻找 n_neighbors 个近邻;
  2. 估计该样本的局部距离尺度;
  3. 构造局部模糊邻域;
  4. 将所有局部邻域合并为一个加权图;
  5. 在低维空间中优化一个图交叉熵目标,使高权重边尽量保持连接,同时控制不应连接的点。

可把高维邻域图表示为边权 wijw_{ij}。低维空间中,常见实现用某种随距离衰减的连接概率 w^ij\hat w_{ij},并优化类似:

C=(i,j)[wijlogwijw^ij+(1wij)log1wij1w^ij].C= \sum_{(i,j)} \left[ w_{ij}\log\frac{w_{ij}}{\hat w_{ij}} + (1-w_{ij})\log\frac{1-w_{ij}}{1-\hat w_{ij}} \right].

具体函数形式与实现参数有关,但核心区别是:UMAP 的输入不是完整的两两距离矩阵,而是由近邻构造的加权图。

6.2 关键参数

n_neighbors

它控制局部与全局的权衡:

  • 较小值更强调局部结构,可能得到更多细小簇;
  • 较大值考虑更宽的邻域,可能更好地呈现连续结构,但局部簇边界会变弱。

它不是模型要找的类别数。

min_dist

它控制低维空间中相邻点可以压缩到多近:

  • 较小值允许形成更紧的团;
  • 较大值通常使点云更松散。

它改变的是低维布局的紧密程度,不等价于“真实簇内距离”。

metric

metric 决定近邻如何计算。欧氏距离适用于某些连续数值特征;余弦距离常用于方向比绝对大小更重要的文本或嵌入向量。若度量不符合数据语义,后续的图结构就已经错误,调参无法完全修复。

6.3 UMAP 与 t-SNE 的差异

两者都可用于二维可视化,但机制和使用边界不同:

维度 t-SNE UMAP
主要结构 概率邻域分布 近邻图与模糊拓扑
重点 局部邻域 局部结构,并尝试保留更多全局图结构
低维坐标的全局距离 通常不可靠 也不能默认可靠
参数直觉 perplexity n_neighbors、min_dist
新样本映射 常见实现主要面向批量拟合 部分实现支持 transform,但有适用条件
结果 受随机优化和参数影响 同样受图构造、优化和参数影响

“UMAP 保留全局结构、t-SNE 只保留局部结构”是有用的经验概括,但不是严格保证。UMAP 的全局布局仍然由近邻图和优化目标产生,不能因此把二维坐标轴或簇间距离解释成精确的原空间测量。

6.4 UMAP 代码示例

umap-learn 是 scikit-learn 生态之外的常用第三方实现,需要单独安装:

python -m pip install umap-learn

示例:

import matplotlib.pyplot as plt
import umap.umap_ as umap

from sklearn.datasets import load_digits
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler

digits = load_digits()
X, _, y, _ = train_test_split(
    digits.data.astype("float64"),
    digits.target,
    train_size=1200,
    stratify=digits.target,
    random_state=42
)

# 对连续像素特征做标准化;是否标准化必须依据数据语义决定
X_scaled = StandardScaler().fit_transform(X)

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

Z_umap = reducer.fit_transform(X_scaled)

plt.figure(figsize=(6, 5))
plt.scatter(
    Z_umap[:, 0],
    Z_umap[:, 1],
    c=y,
    cmap="tab10",
    s=10,
    alpha=0.8
)
plt.title("UMAP")
plt.xlabel("UMAP 1")
plt.ylabel("UMAP 2")
plt.show()

这里的 random_state 常用于复现实验,但在某些实现中,为了固定随机结果,可能降低并行度。参数与实现版本有关,应以安装版本的文档为准。

如果需要对新样本调用 transform,必须保留同一个已拟合的 UMAP 对象,并确保新样本经过完全相同的预处理:

# 假设 reducer 已经在训练集上 fit
new_X_scaled = scaler.transform(new_X)
new_Z = reducer.transform(new_X_scaled)

但这不表示 UMAP 像 PCA 一样拥有简单、稳定、线性的投影函数。新点的映射依赖训练时建立的邻域图和实现提供的近似变换;当新数据来自明显不同的分布时,结果可能不可靠。生产系统应通过时间切分、漂移测试和下游任务指标验证,而不能只看新点是否落在某个二维簇内。


七、完整比较:PCA、SVD、t-SNE 与 UMAP 到底保留什么

方法 映射类型 主要优化目标 是否容易重构 是否适合作为生产特征 是否适合二维可视化
PCA 线性 最大方差、最小平方重构误差 是,近似重构 经常适合 适合
SVD 线性低秩分解 最佳秩 kk 近似 是,近似重构 经常适合 适合
t-SNE 非线性、邻域概率映射 最小化 KL(PQ)\operatorname{KL}(P|Q) 通常不适合 通常不作为通用生产特征 主要适合
UMAP 非线性、近邻图优化 保持模糊邻域图 不应默认可逆 需经过严格验证 适合

更具体地说:

  • 若需要解释方差、近似重构或稳定的线性变换,优先考虑 PCA;
  • 若输入是大规模稀疏矩阵,尤其是文本矩阵,考虑 TruncatedSVD;
  • 若目标是观察局部邻域,t-SNE 是常用工具;
  • 若希望在邻域图基础上兼顾更大范围结构,或需要某些实现提供的新样本映射能力,可以考虑 UMAP;
  • 如果最终模型对预测性能负责,应直接用验证集评估降维后的下游模型,而不是用二维图替代评测。

八、可视化边界:二维图不能证明什么

8.1 二维距离通常不能解释为原空间距离

PCA 在 kk 维子空间中保留的是线性投影后的几何关系,但即使是 PCA,二维中的欧氏距离也只是原空间距离的投影结果。被丢弃的主成分可能包含重要距离信息。

t-SNE 和 UMAP 的情况更严格:

  • 点的绝对位置通常没有意义;
  • 整体旋转、平移不会改变结构;
  • 不同运行之间坐标轴不能对齐;
  • 簇间距离、簇面积和空白区域不应直接作定量解释。

例如,两个类别在 t-SNE 图中相距很远,不代表它们在原始嵌入空间的平均距离一定比另两个类别更大。

8.2 可视化不能替代标签评测

如果用标签给散点着色,颜色只是帮助观察。它不能证明降维算法使用了标签,也不能证明簇是无监督发现的真实类别。

应区分:

  • 无监督拟合:降维算法只看 XX
  • 监督评估:用 yy 检查低维表示是否有助于分类或检索;
  • 监督降维:算法在拟合时显式使用 yy,例如线性判别分析。

如果同一批数据既用于拟合降维、选择参数,又用于报告分类性能,会产生乐观偏差。降维器必须在训练折中拟合,并在验证折或测试折中只调用 transform。对 t-SNE 这类主要用于可视化的方法,则应明确它不是标准的可泛化特征工程流程。

8.3 高维簇不一定在二维仍然分离

考虑三个高维类别,其中区分它们的信息只存在于第 20 个方向,而前两个方向主要包含与标签无关的大方差噪声。PCA 的二维图可能混合三个类别,但这不表示数据不可分类;它只表示前两个主成分没有保留有效的类别方向。

反过来,t-SNE 或 UMAP 可能把局部相似样本组织成清晰的簇,但这些簇可能来自:

  • 采样批次;
  • 图像背景;
  • 文本长度;
  • 设备或地区;
  • 预处理流程;
  • 数据泄漏字段。

因此,视觉分离必须回到特征来源、分层统计和独立测试集进行验证。

8.4 降维图可能泄露敏感信息

高维表示可能包含:

  • 人脸、声音和生物特征;
  • 用户身份关联;
  • 医疗或财务属性;
  • 训练语料来源;
  • 访问权限或业务标签。

把降维图导出到 notebook、日志、监控面板或外部协作工具,仍然是在导出原始信息的压缩表示。二维化不会自动满足匿名化、差分隐私或访问控制要求。生产系统中应把可视化数据视为受权限管理的数据资产,并限制样本量、字段和导出范围。


九、常见失败表现与诊断方法

9.1 t-SNE 每次运行图都不同

可能原因:

  • 使用了随机初始化;
  • 学习率或早期夸大导致优化落入不同局部解;
  • 数据本身结构弱;
  • perplexity 不适合样本规模;
  • 输入特征尺度或距离度量错误。

诊断方法是固定 random_state 先复现,再改变多个随机种子和 perplexity,检查哪些邻域关系稳定。不能只挑选最符合预期的一次图。

9.2 所有方法都出现几个“漂亮的岛”

可能原因不是算法发现了真实类别,而是:

  • 输入数据已经带有批次效应;
  • 特征中有标签泄漏;
  • 样本之间存在重复或近重复;
  • 颜色标签形成了视觉确认偏差;
  • 非线性方法把连续变化人为切分。

可检查每个簇的元数据分布、批次比例、近重复样本以及原空间距离。若类别信息只在某个数据采集批次中出现,模型可能学到的是批次而非语义。

9.3 PCA 解释方差很高,但分类很差

解释方差衡量的是 XX 的总体变异,不是 XX 与标签 yy 的关联。设:

X=Xlarge variance+Xsmall signal,X = X_{\text{large variance}} + X_{\text{small signal}},

如果标签只依赖第二项,保留 95% 方差仍可能丢弃分类信号。此时应比较:

  • 不降维的基线;
  • 不同 kk 的 PCA;
  • 正则化模型;
  • 监督方法;
  • 直接使用原始或任务专用嵌入。

9.4 UMAP 的结果在不同参数下变化很大

这通常说明局部图结构对尺度或邻域范围敏感。应检查:

  • metric 是否符合特征语义;
  • 特征是否需要标准化;
  • n_neighbors 改变后哪些关系仍稳定;
  • 新旧数据的分布是否一致;
  • 图中的簇是否在原空间近邻指标中存在。

参数敏感不一定说明 UMAP 错误,但说明不能把某一组参数产生的二维布局当作唯一事实。


十、机器学习、深度学习与生成式 AI 中的使用边界

10.1 传统机器学习

对于表格数据,PCA 可以减少高度相关特征,降低线性模型的计算成本,并缓解某些多重共线性问题。但树模型通常不需要 PCA,因为树的分裂机制不依赖线性正交坐标;对树模型盲目 PCA 还可能损失可解释的原始特征边界。

对文本和推荐系统中的稀疏矩阵,TruncatedSVD 可以生成低维潜在表示。是否有价值应通过召回率、排序指标、延迟、内存和模型稳定性共同判断。

10.2 深度学习表示

神经网络隐藏层、视觉特征和 Transformer embedding 往往有数百到数千维。把它们用 t-SNE 或 UMAP 映射到二维,可以帮助观察:

  • 类别或主题是否形成局部结构;
  • 训练过程中表示是否发生塌缩;
  • 不同数据切片是否混合;
  • 异常样本是否落在边缘。

但二维图不能证明 embedding 已经具有良好的检索性能。应同时评估:

  • Recall@K、MRR、nDCG;
  • 类内与类间相似度;
  • 跨时间和跨域稳定性;
  • 近重复与数据泄漏;
  • 下游分类或生成任务质量。

10.3 生成式 AI

在生成式 AI 系统中,可以对以下对象降维:

  • 文档 chunk 的 embedding;
  • 查询与文档的联合 embedding;
  • 生成样本的语义表示;
  • 训练过程中的隐藏状态;
  • 不同模型版本的输出表示。

但必须注意比较空间是否一致。两个模型输出的 embedding 即使维度相同,也未必共享同一坐标系;直接把它们画在同一张 PCA 图上通常没有意义,除非使用共同的编码器、对齐变换或明确的比较方法。

对 RAG 系统,UMAP 或 t-SNE 图中出现“文档簇”不等于检索器召回正确。应使用查询级别的 Recall@K、MRR、答案支持率和人工事实一致性评估。对生成结果做降维也不能替代毒性、隐私、事实性和安全评测。


十一、生产管道中的状态、数据流与故障路径

一个合理的降维管道可以表示为:

flowchart LR
    A[原始数据] --> B[训练/验证/测试切分]
    B --> C[预处理拟合]
    C --> D[降维器拟合]
    D --> E[下游模型或可视化]
    E --> F[独立评测]
    C --> G[版本化预处理]
    D --> H[版本化降维器]
    G --> I[线上新样本预处理]
    H --> J[线上变换或离线分析]
    I --> J

关键路径是:

  1. 先切分数据;
  2. 只用训练集拟合均值、标准差、词表、主成分或近邻图;
  3. 验证集和测试集只能使用已拟合对象进行变换;
  4. 保存预处理和降维器的版本;
  5. 线上新样本必须使用同一列顺序、同一词表、同一尺度和同一距离定义。

常见故障路径包括:

  • 数据泄漏:在全量数据上先标准化或先 PCA,再切分训练测试;
  • 特征错位:线上列顺序变化,导致 PCA 方向作用于错误特征;
  • 分布漂移:新样本远离训练数据,低维坐标仍被强行生成;
  • 资源故障:对大规模数据使用完整距离矩阵,导致内存耗尽;
  • 并发不一致:多个任务同时覆盖同一个降维器文件或缓存;
  • 版本不一致:训练环境和推理环境的算法实现、参数默认值或序列化格式不同。

对于 PCA 和 TruncatedSVD,线上变换通常是确定的矩阵运算,延迟和状态管理相对简单。对于 t-SNE,批量新增样本的稳定映射不是其最自然的使用模式;如果系统需要每天对新数据进行一致坐标投影,PCA、固定的 UMAP 变换器或专门训练的编码器通常更容易验证。


十二、如何选择 kk 或二维参数

PCA / SVD

可以从三个角度选择维度 kk

  1. 累计解释方差:例如 90%、95% 或 99%,适合重构和压缩;
  2. 验证集任务性能:观察分类、回归、检索指标随 kk 的变化;
  3. 成本约束:衡量内存、存储、网络传输和推理延迟。

不能因为某个 kk 达到 95% 方差,就断言它是任务最优维度。应画出 kk 与任务指标、重构误差和成本之间的关系。

t-SNE

至少检查多个 perplexity 和随机种子。重点观察:

  • 原空间近邻是否在图中仍相近;
  • 类别或切片结构是否稳定;
  • 是否出现极端拥挤或离群点;
  • 图是否只是颜色标签的视觉分离。

UMAP

至少检查多个 n_neighborsmin_dist 和合理的 metric。如果目标是探索局部结构,应重点检查小邻域保持率;如果目标是比较全局关系,应同时报告原空间距离或图距离,而不是只测二维欧氏距离。


十三、一个可复现的评估框架

降维结果至少应同时报告“图”和“数”:

import numpy as np
from sklearn.neighbors import NearestNeighbors

def neighbor_preservation(X_high, Z_low, k=10):
    """计算高维和低维 k 近邻集合的平均交集比例。"""
    nn_high = NearestNeighbors(n_neighbors=k + 1).fit(X_high)
    nn_low = NearestNeighbors(n_neighbors=k + 1).fit(Z_low)

    high_idx = nn_high.kneighbors(return_distance=False)[:, 1:]
    low_idx = nn_low.kneighbors(return_distance=False)[:, 1:]

    scores = []
    for a, b in zip(high_idx, low_idx):
        scores.append(len(set(a).intersection(b)) / k)

    return float(np.mean(scores))

输入 X_high 是用于计算高维邻域的特征,Z_low 是降维坐标,函数输出平均近邻保持率。使用时必须明确高维度量是否需要标准化、是否使用余弦距离,以及评估数据是否独立于拟合过程。

例如:

print("PCA neighbor preservation:",
      neighbor_preservation(X_scaled, Z_pca, k=10))

print("t-SNE neighbor preservation:",
      neighbor_preservation(X_scaled, Z_tsne, k=10))

这个指标只能衡量局部邻域,不等价于任务性能,也不能证明全局几何被保持。完整评估还应包括:

  • 重构误差:适用于 PCA 或 SVD;
  • 下游任务指标:分类、回归、聚类或检索;
  • 邻域保持率:适用于局部结构;
  • 多随机种子稳定性;
  • 时间切分和跨域验证;
  • 资源成本:训练时间、内存、存储和线上延迟;
  • 权限与隐私检查:哪些样本和特征允许被导出。

十四、最终边界

PCA 是线性方差压缩方法,SVD 是通用的低秩矩阵分解;对中心化矩阵做 SVD,可以计算 PCA。t-SNE 和 UMAP 都是非线性邻域可视化方法,但它们优化的对象不同:t-SNE 主要匹配高维与低维的概率邻域分布,UMAP 主要从近邻图和模糊拓扑结构出发进行布局。

最重要的区分是:

  • PCA/SVD 的低维坐标可以具有压缩和重构含义
  • t-SNE/UMAP 的二维坐标主要具有探索和可视化含义
  • 任何二维图都不能单独证明类别、因果关系、全局距离或模型质量
  • 降维器必须和预处理、数据切分、版本、权限、成本及下游评测放在同一个生产系统中管理

当目标是压缩或稳定特征变换时,应优先从 PCA 或 SVD 开始;当目标是观察复杂表示的局部结构时,可以使用 t-SNE 或 UMAP;当图形结论需要进入模型、产品或决策流程时,必须回到原空间指标、独立评测和数据治理上验证。


系列导航与关联阅读

官方资料

本文依据研究论文、标准组织与主流框架官方文档重新梳理;正文、示例与工程清单由 WR BLOG 编写。