跳转至

13 - 降维与流形学习

降维与流形学习图

🎯 为什么需要降维?

维度灾难 (Curse of Dimensionality)

Text Only
高维空间的问题:
1. 数据稀疏性
   - 1000个样本在3维空间:密集
   - 1000个样本在1000维空间:极度稀疏

2. 距离失效
   - 高维空间中,所有点对的距离趋于相近
   - 欧氏距离失去区分能力

3. 计算复杂度
   - 存储:O(d²) 的协方差矩阵
   - 计算:矩阵分解复杂度为 O(d³),高维时计算量巨大

4. 可视化困难
   - 人类只能直观理解3维及以下

降维的好处

Text Only
✅ 减少存储和计算成本
✅ 去除噪声和冗余特征
✅ 缓解过拟合
✅ 便于可视化
✅ 发现数据的内在结构

📐 线性降维方法

PCA (主成分分析)

已在 03-无监督学习.md 中详细介绍,这里补充进阶内容。

PCA的数学本质

Text Only
目标:找到投影方向,使得投影后的方差最大

数学推导:
给定中心化数据 X (n×d)
寻找投影向量 w,使得 Var(Xw) 最大

Var(Xw) = w^T X^T X w / n = w^T C w

约束:||w|| = 1

拉格朗日函数:
L = w^T C w - λ(w^T w - 1)

求导得:Cw = λw

→ w 是协方差矩阵 C 的特征向量
→ λ 是对应的特征值
→ 最大方差 = 最大特征值

核PCA (Kernel PCA)

Text Only
问题:PCA只能找到线性投影
解决:通过核函数映射到高维空间,再PCA

步骤:
1. 选择核函数 K(x,y)
2. 计算核矩阵 K (n×n)
3. 对K进行特征分解
4. 投影:新坐标 = K · 特征向量

常用核函数:
- 多项式核:K(x,y) = (x·y + c)^d
- RBF核:K(x,y) = exp(-γ||x-y||²)
Python
from sklearn.decomposition import KernelPCA

# 核PCA
kpca = KernelPCA(
    n_components=2,
    kernel='rbf',      # 或 'poly', 'sigmoid', 'linear'
    gamma=0.1
)

X_kpca = kpca.fit_transform(X)

LDA (线性判别分析)

核心思想

有监督降维:最大化类间距离,最小化类内距离

Text Only
目标:找到投影方向,使得:
- 不同类的中心尽可能远(类间散度大)
- 同类样本尽可能聚集(类内散度小)

优化目标:
J(w) = (类间散度) / (类内散度) = (w^T S_b w) / (w^T S_w w)

其中:
S_b = 类间散度矩阵
S_w = 类内散度矩阵

与PCA的区别

Text Only
PCA:
- 无监督
- 最大化投影方差
- 保留全局结构

LDA:
- 有监督(需要标签)
- 最大化类间可分性
- 适合分类任务预处理

代码实现

Python
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis

# LDA降维
lda = LinearDiscriminantAnalysis(n_components=2)
X_lda = lda.fit_transform(X, y)

# 注意:n_components <= min(n_classes - 1, n_features)
print(f"LDA降维后形状: {X_lda.shape}")

# 可视化
plt.scatter(X_lda[:, 0], X_lda[:, 1], c=y, cmap='viridis')
plt.title('LDA降维可视化')
plt.show()

其他线性方法

NMF (非负矩阵分解)

Text Only
约束:所有元素非负
X ≈ W × H

应用:
- 图像分析
- 文本主题模型
- 音频信号处理
Python
from sklearn.decomposition import NMF

nmf = NMF(n_components=10, random_state=42)
W = nmf.fit_transform(X)  # 基矩阵
H = nmf.components_       # 系数矩阵

SVD (奇异值分解)

已在 00-数学基础.md 中介绍。

Python
from sklearn.decomposition import TruncatedSVD

svd = TruncatedSVD(n_components=50)
X_svd = svd.fit_transform(X)

🌊 非线性降维 - 流形学习

什么是流形?

Text Only
直观理解:
- 高维空间中的低维结构
- 局部是欧几里得的,整体是非线性的

例子:
- 地球表面:3维空间中的2维流形
- 瑞士卷:3维空间中的2维流形
- 人脸图像:高维像素空间中的低维流形

t-SNE (t-Distributed Stochastic Neighbor Embedding)

已在 03-无监督学习.md 中介绍,这里补充原理。

数学原理

Text Only
核心思想:保持局部邻域关系

步骤1:在高维空间计算相似度
p(j|i) = exp(-||x_i - x_j||² / 2σ_i²) / Σ_{k≠i} exp(-||x_i - x_k||² / 2σ_i²)

步骤2:在低维空间计算相似度(用t分布)
q(j|i) = (1 + ||y_i - y_j||²)^(-1) / Σ_{k≠i} (1 + ||y_i - y_k||²)^(-1)

步骤3:最小化KL散度
KL(P||Q) = Σ_i Σ_j p(j|i) log(p(j|i) / q(j|i))

为什么用t分布?
- 重尾特性:防止拥挤问题 (crowding problem)
- 允许低维空间中保持更多的局部结构

使用技巧

Python
from sklearn.manifold import TSNE

# 推荐流程
# 1. 先用PCA降到中等维度(如50维)
from sklearn.decomposition import PCA
pca = PCA(n_components=50)
X_pca = pca.fit_transform(X_scaled)

# 2. 再用t-SNE降到2维
tsne = TSNE(
    n_components=2,
    perplexity=30,      # 通常5-50
    learning_rate=200,  # 通常10-1000
    n_iter=1000,
    random_state=42
)
X_tsne = tsne.fit_transform(X_pca)

# 注意:t-SNE计算复杂度高,不适合大数据

UMAP (Uniform Manifold Approximation and Projection)

核心优势

Text Only
相比t-SNE:
✅ 更快(尤其是大数据)
✅ 更好的全局结构保持
✅ 支持新数据变换(transform)
✅ 可以控制局部/全局权衡

数学思想

Text Only
基于两个假设:
1. 数据均匀分布在黎曼流形上
2. 黎曼度量是局部欧几里得的(常数)

步骤:
1. 构建高维空间的模糊拓扑表示
2. 构建低维空间的模糊拓扑表示
3. 最小化两者的交叉熵

代码实现

Python
import umap

# UMAP降维
reducer = umap.UMAP(
    n_components=2,
    n_neighbors=15,      # 控制局部/全局权衡
    min_dist=0.1,        # 控制点之间的最小距离
    metric='euclidean',  # 距离度量
    random_state=42
)

X_umap = reducer.fit_transform(X_scaled)

# 可视化
plt.scatter(X_umap[:, 0], X_umap[:, 1], c=y, cmap='viridis', s=5)
plt.title('UMAP降维可视化')
plt.show()

# UMAP支持transform新数据
# reducer.transform(X_new)

参数调优

Text Only
n_neighbors:
- 小值(2-5):关注局部结构,可能发现细粒度聚类
- 大值(50-100):关注全局结构,保持整体形状

min_dist:
- 小值(0.001-0.1):点更聚集,显示局部结构
- 大值(0.5-1.0):点更分散,显示全局结构

其他流形学习方法

ISOMAP

Text Only
思想:保持测地距离(流形上的最短路径)

步骤:
1. 构建k近邻图
2. 计算图中所有点对的测地距离(Floyd或Dijkstra)
3. 对距离矩阵进行MDS
Python
from sklearn.manifold import Isomap

isomap = Isomap(n_components=2, n_neighbors=10)
X_isomap = isomap.fit_transform(X)

LLE (局部线性嵌入)

Text Only
思想:保持局部线性关系

假设:每个点可以表示为邻居的线性组合
目标:在低维空间中保持这种线性关系
Python
from sklearn.manifold import LocallyLinearEmbedding

lle = LocallyLinearEmbedding(n_components=2, n_neighbors=10)
X_lle = lle.fit_transform(X)

MDS (多维缩放)

Text Only
思想:保持点之间的距离关系

目标:min Σ (d_ij - ||y_i - y_j||)²
Python
from sklearn.manifold import MDS

mds = MDS(n_components=2, random_state=42)
X_mds = mds.fit_transform(X)

📊 方法对比

线性方法对比

方法 类型 特点 适用场景
PCA 无监督 最大化方差,全局结构 通用降维,去噪
LDA 有监督 最大化类间可分性 分类预处理
NMF 无监督 非负约束,可解释性强 图像、文本
SVD 无监督 矩阵分解,数值稳定 推荐系统,文本

非线性方法对比

方法 速度 全局结构 新数据变换 适用场景
t-SNE 不支持 可视化,小数据
UMAP 支持 可视化,大数据
ISOMAP 中等 中等 不支持 测地距离重要
LLE 中等 不支持 局部线性结构
MDS 不支持 距离保持重要

🎯 实践建议

选择指南

Text Only
第一步:是否需要非线性?
├── 是 → 使用流形学习方法
│   ├── 数据量大 (>10K) → UMAP
│   └── 数据量小 → t-SNE
└── 否 → 使用线性方法
    ├── 有标签 → LDA
    └── 无标签 → PCA

完整流程示例

Python
import numpy as np
import matplotlib.pyplot as plt
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
import umap

# 1. 数据标准化(必须!)
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

# 2. 先用PCA去除噪声,降到中等维度
pca = PCA(n_components=50)
X_pca = pca.fit_transform(X_scaled)

print(f"PCA保留方差比例: {pca.explained_variance_ratio_.sum():.2%}")

# 3. 再用UMAP降到2维可视化
reducer = umap.UMAP(n_components=2, random_state=42)
X_umap = reducer.fit_transform(X_pca)

# 4. 可视化
plt.figure(figsize=(10, 8))
scatter = plt.scatter(X_umap[:, 0], X_umap[:, 1], c=y, cmap='tab10', s=5)
plt.colorbar(scatter)
plt.title('UMAP Visualization')
plt.show()

常见陷阱

Text Only
❌ 不降维直接可视化高维数据
→ 必须使用降维方法

❌ 不降维直接用t-SNE/UMAP
→ 先PCA预处理,加速且去噪

❌ 忽略数据标准化
→ 不同尺度的特征会主导结果

❌ 过度解读t-SNE/UMAP的距离
→ 只保持局部结构,全局距离不可靠

❌ 用降维后的数据直接做分类
→ 信息损失,性能可能下降

💡 总结

Text Only
降维的本质:
在保留重要信息的前提下,减少数据维度

线性方法:
- 简单、快速、可解释
- 适合线性结构的数据

非线性方法(流形学习):
- 能发现复杂的非线性结构
- 计算成本高,主要用于可视化

选择原则:
1. 先尝试线性方法
2. 可视化用UMAP或t-SNE
3. 始终标准化数据
4. 注意信息损失与任务需求的平衡

下一步:学习 14-贝叶斯方法.md,掌握概率化建模方法!