高维数据怎样压成几个方向?PCA 的最大方差、重构误差与 SVD
从相关传感器的冗余出发,统一 PCA 的最大方差与最小重构视角,手算主轴,并用 SVD 和 scikit-learn 1.9 实现可诊断降维。
上一篇的 K 均值在原始特征空间比较样本到中心的欧氏距离。若 100 个传感器中许多通道测量同一种物理变化,模型会在大量相关坐标上重复计算;可视化、存储和后续学习也都会变难。
主成分分析(Principal Component Analysis,PCA)不使用标签,而是寻找数据变化最强的一组正交方向,再把样本投影过去。本文只围绕三个等价视角展开:最大化投影方差、最小化线性重构误差,以及用奇异值分解稳定地算出主轴。
01 删除某些列为何不是理想的降维?#
假设温度传感器 A 和 B 几乎同步变化。直接删掉 B 能减少一维,但会完全丢弃 B 的独立噪声与校准信息。PCA 不选择某一根坐标轴,而是学习一个组合方向,例如:
x₂(传感器 B)
▲
│ ●
│ ●
│ ● 数据主要沿斜线变化
│ ● ╱ v₁(第一主轴)
│ ● ╱
└────────╱──────────────────► x₁(传感器 A)
垂直于 v₁ 的变化很小text原始变量仍可通过主轴系数解释,但新特征不再等于单独某一列。PCA 是特征提取(Feature Extraction),不是特征选择(Feature Selection)。
02 第一步为什么必须中心化?#
输入:
先计算每个特征的训练均值:
中心化矩阵:
若不减均值,最大的能量方向可能只是从原点指向数据云中心,而不是数据真正变化的方向。之后所有验证集和新样本都必须减训练集均值,不能各自重新中心化。
样本协方差矩阵为:
它的对角线是各特征方差,非对角线是共同变化。PCA 要在这个几何中寻找主轴。
03 “最大方差方向”怎样写成优化问题?#
取单位向量 ,满足 。每个样本投影为:
全部投影 。投影方差为:
第一主成分方向解决:
用拉格朗日乘子求导:
因此 是协方差矩阵最大特征值 对应的特征向量。后续方向继续最大化方差,并要求与已有方向正交。保留 个方向时:
低维表示为:
04 最大方差为何等价于最小重构误差?#
投影后可把样本映回原空间:
PCA 同时解决秩为 的正交线性重构问题:
总中心化能量是固定的。投影方向保留得越多,垂直方向丢掉的能量越少,因此“最大保留方差”和“最小平方重构误差”是同一件事的两面。
训练:X [N,D]
│ 减 mean [D]
▼
Xc [N,D] ── SVD ──► components [M,D]
│ │
└──── @ components.T ─────┘
▼
Z [N,M]
重构:Z [N,M] @ components [M,D] + mean [D]
▼
X_hat [N,D]text05 用三个二维点手算第一主轴#
取三个已中心化样本:
协方差矩阵为:
两个特征值为 、,对应单位方向可取:
只保留第一主成分:
重构 恰好等于原矩阵,误差为 0,因为三个点完全落在直线 上。解释方差比为:
注意 取相反数也同样正确:主轴的符号不唯一,相应的 也会整体变号,但重构与解释方差不变。
06 为什么实现通常直接做 SVD?#
显式形成 协方差矩阵可能耗费大量内存,还会放大数值条件问题。对中心化矩阵做奇异值分解(Singular Value Decomposition,SVD):
其中:
- :左奇异向量;
- ;
- :右奇异向量,行就是主轴;
- (经济型分解下再受矩阵秩限制)。
协方差特征值与奇异值满足:
所以不需要先计算 也能得到主轴与解释方差。
07 用 NumPy 写出 PCA 本体#
import numpy as np
X = np.array([
[-1.0, -1.0],
[0.0, 0.0],
[1.0, 1.0],
], dtype=np.float64) # [N=3,D=2]
mean = X.mean(axis=0) # [D]
X_centered = X - mean # [N,D]
U, singular_values, Vt = np.linalg.svd(
X_centered,
full_matrices=False,
)
n_components = 1
components = Vt[:n_components] # [M=1,D]
Z = X_centered @ components.T # [N,M]
X_reconstructed = Z @ components + mean # [N,D]
explained_variance = singular_values**2 / (X.shape[0] - 1)
explained_variance_ratio = explained_variance / explained_variance.sum()
reconstruction_mse = np.mean((X - X_reconstructed) ** 2)
assert components.shape == (1, 2)
assert Z.shape == (3, 1)
assert np.allclose(components @ components.T, np.eye(1))
assert np.isclose(explained_variance_ratio[0], 1.0)
assert np.isclose(reconstruction_mse, 0.0)python实际数据可能存在相等或非常接近的奇异值,此时对应子空间仍稳定,但子空间内部的单根主轴可能旋转。不要仅凭某个载荷(loading)的微小变化就断言数据机制改变。
08 用 scikit-learn 1.9 正确落地#
按照当前官方 PCA 应用程序接口(Application Programming Interface,API) ↗,模型会自动中心化输入,但不会自动按列缩放。若各特征单位不同且希望等权,可把缩放放进同一条流水线(Pipeline):
import numpy as np
from sklearn.decomposition import PCA
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
pipeline = make_pipeline(
StandardScaler(),
PCA(
n_components=0.95,
svd_solver='full',
whiten=False,
),
)
Z_train = pipeline.fit_transform(X_train) # [N,M]
Z_new = pipeline.transform(X_new) # [Q,M]
pca = pipeline.named_steps['pca']
scaled_reconstruction = pca.inverse_transform(Z_new) # [Q,D]
X_reconstructed = pipeline.named_steps['standardscaler'].inverse_transform(
scaled_reconstruction
)
print(pca.n_components_) # 实际 M
print(pca.components_.shape) # [M,D]
print(pca.explained_variance_.shape) # [M]
print(pca.explained_variance_ratio_.sum()) # 至少约 0.95
print(pca.singular_values_.shape) # [M]
print(pca.mean_.shape) # [D],缩放空间中的训练均值
assert Z_new.shape[1] == pca.n_components_
assert np.all(np.diff(pca.explained_variance_) <= 0)
assert np.allclose(
pca.components_ @ pca.components_.T,
np.eye(pca.n_components_),
atol=1e-10,
)python这里 n_components=0.95 只在 svd_solver='full' 时按累计解释方差阈值选维数。fit_transform 的训练输出和后续 transform 都使用训练均值与训练主轴;不能在测试集上重新 fit 以“适配”测试分布。
09 求解器怎样影响时间、内存与精度?#
scikit-learn 1.9 的主要选择如下:
svd_solver | 核心计算 | 适用形状 | 重要限制 |
|---|---|---|---|
full | 精确完整 SVD 后截断 | 中小数据、需要精确基线 | 大矩阵成本高 |
covariance_eigh | 构造协方差后特征分解 | 且 较小 | 协方差占 内存,数值条件更差 |
randomized | 随机截断 SVD | 大矩阵且只取少量 | 近似;固定 random_state,检查误差 |
arpack | 稀疏截断 SVD | 只取少数分量 | 必须 |
auto | 根据形状与 选择 | 合理默认起点 | 版本升级可能改变选择策略 |
randomized 的 n_oversamples、iterated_power 与 power_iteration_normalizer 控制速度—精度权衡。不要在没有误差基线的情况下随意压低它们。若可复现性或跨版本一致性重要,应显式写求解器和随机种子,并记录库版本。
10 维数 M 应该怎样选?#
常见做法是画累计解释方差:
但 不是普适规则。应至少同时检查:
- 重构误差:验证样本在不同 下的均方重构误差;
- 下游任务:在完整 Pipeline 内交叉验证分类、回归、检索或聚类指标;
- 稳定性:重采样后比较主子空间,而不只比较单根向量符号;
- 资源约束:确认存储、延迟和可视化维数是否达到项目目标。
若 PCA 是监督模型的预处理, 必须在每个训练折内部选择。先对全数据拟合 PCA 再交叉验证会把验证折的均值与协方差信息泄漏给训练过程。
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import GridSearchCV
model = make_pipeline(
StandardScaler(),
PCA(svd_solver='full'),
LogisticRegression(max_iter=2000),
)
# GridSearchCV:带交叉验证的网格搜索
search = GridSearchCV(
model,
param_grid={'pca__n_components': [2, 5, 10, 20]},
scoring='neg_log_loss',
cv=5,
)
search.fit(X_train, y_train)python11 标准化、白化和稀疏输入不要混为一谈#
**标准化(Standardization)**发生在 PCA 之前,把每个原始特征缩放到相近方差;它改变主轴关注的几何。若米、千克和元混在一起,通常需要明确处理量纲。若所有像素采用同一测量尺度,保留自然方差也可能更合理。
**白化(Whitening)**发生在 PCA 投影时。whiten=True 会进一步按奇异值缩放各主成分,使输出分量方差约为 1。它去掉了分量之间原有的相对方差尺度,可能帮助假设各向同性的下游模型,也可能丢掉有用强度信息。
稀疏输入不能随意中心化,因为减去均值通常会把零填成非零并造成内存爆炸。当前 PCA 只在部分求解器上支持稀疏输入;大规模词袋数据常用不中心化的 TruncatedSVD。后者有时被称为潜在语义分析,但它与严格中心化 PCA 的目标并不相同。
12 怎样调试与监控 PCA?#
建议记录以下量,而不只是二维散点图:
ratio = pca.explained_variance_ratio_
assert np.isfinite(ratio).all()
assert np.all(ratio >= 0)
assert ratio.sum() <= 1.0 + 1e-12
reconstruction = pipeline.inverse_transform(Z_train)
per_feature_mse = np.mean((X_train - reconstruction) ** 2, axis=0) # [D]
print('selected dimensions:', pca.n_components_)
print('cumulative explained variance:', ratio.sum())
print('worst reconstructed feature:', np.argmax(per_feature_mse))python部署后还应监控训练均值与新数据均值的偏移、投影分数分布、各主成分方差、重构误差和缺失值比例。重构误差突然上升可能表示分布漂移、传感器故障或新模式出现,但不是自动的异常因果诊断。
常见错误包括:
- 在划分数据前拟合缩放器或 PCA;
- 忘记中心化,或让训练与推理使用不同均值;
- 把
components_当成[D,M],实际形状是[M,D]; - 用绝对载荷大小解释变量,却忽略标准化方式和主轴符号不唯一;
- 把二维投影视图中的重叠直接当成原空间不可分;
- 认为 95% 方差就等于保留 95% 任务信息;
- 对稀疏词袋先
toarray(),导致内存耗尽。
13 PCA 会在哪些场景失败?#
PCA 是全局线性方法,主要失败边界是:
- 数据位于弯曲流形,例如环形或瑞士卷;
- 少数异常值制造巨大方差,主轴被异常方向吸引;
- 高方差是无关噪声,低方差才是目标信号;
- 主成分是许多特征的稠密组合,难以解释和部署;
- 不同群体拥有不同局部方向,一个全局子空间会混合它们;
- 新数据分布漂移,旧均值和主轴不再代表当前结构。
14 与相近方法的边界#
| 方法 | 是否用标签 | 核心目标 | 主要区别 |
|---|---|---|---|
| PCA | 否 | 最大方差、最小线性重构误差 | 全局线性、正交稠密主轴 |
| LDA 降维 | 是 | 增大类间散布、减小类内散布 | 监督投影,最多 个判别方向 |
| 特征选择 | 可选 | 保留部分原始列 | 不组合特征,解释更直接 |
| TruncatedSVD | 否 | 低秩近似,通常不中心化 | 适合大型稀疏矩阵 |
| Kernel PCA | 否 | 在核特征空间做 PCA | 可表达非线性,但扩展与逆变换更难 |
| 自编码器 | 否或带辅助目标 | 神经网络重构 | 可非线性,训练与调参成本更高 |
15 今天真正需要记住什么?#
PCA 先用训练均值中心化数据,再寻找方差最大的正交方向。保留前 个方向既最大化投影方差,也最小化正交线性重构误差;SVD 可以不显式构造协方差地得到主轴。它压缩的是 PCA 所定义的“方差信息”,不是自动保留语义、因果或下游预测信号。
16 思考题与小练习#
- 对样本 手算均值与协方差。两个特征值有什么关系?第一主轴是否唯一?
- 将某二维数据的第二列乘以 100,比较不标准化 PCA 与
StandardScaler + PCA的第一主轴;解释两者分别回答什么问题。 - 在一个监督任务上,把
PCA放在交叉验证外和 Pipeline 内各评估一次。若分数不同,定位泄漏发生在哪个统计量,并画 —性能—重构误差三条曲线。
相关工作#
- Hotelling (1933), Analysis of a Complex of Statistical Variables into Principal Components ↗:主成分分析的经典统计学表述。
- Eckart & Young (1936), The Approximation of One Matrix by Another of Lower Rank ↗:截断 SVD 最优低秩近似的理论基础。
- Tipping & Bishop (1999), Probabilistic Principal Component Analysis ↗:把 PCA 写成带各向同性噪声的概率潜变量模型。
- Halko, Martinsson & Tropp (2011), Finding Structure with Randomness ↗:大规模随机矩阵分解与随机 SVD 的系统方法。
17 下一篇预告#
PCA 用连续坐标表示样本,K 均值则把每个样本硬分给一个中心。若两个簇明显重叠,我们还希望表达“这个点属于两边的概率各是多少”。下一篇将进入高斯混合模型,从混合分布、软责任度与期望最大化(Expectation-Maximization,EM)的 E 步—M 步循环推导概率聚类。