LDA 是有监督的降维:它知道每个点属于哪一类,于是专门找一个「投影后两类离得最远」的方向。 Demo 里同一份数据, PCA 选的方向分离度只有 0.6866(两团糊在一起),LDA 选的方向 6.7165,差了 9.8 倍—— 因为 PCA 只看方差,根本不知道有「类」这回事。
前面三个算法都是无监督的:没有 y,只能找「数据自己散成什么样」。这一节把 y 请回来。 有了标签,降维的目标就变了——不是「保住最多信息」,而是「保住最能分开类的信息」。 这两个目标经常冲突,Demo 会把它量出来。 注意本节的 LDA 是 Linear Discriminant Analysis,中文叫线性判别分析。 另一个常被叫 LDA 的是 Latent Dirichlet Allocation,中文叫潜在狄利克雷分配。 两者除了缩写一样,没有任何关系,最后一节专门辨析。
一、目标换了:不是保信息,是保可分性
PCA 的问题在这里暴露得很清楚:方差大的方向,不一定分得开类。 想象两类点, 在 x1 方向上都拉得很长(方差大),但两类的中心几乎重合; 在 x2 方向上都挤得很紧(方差小),但中心差得很远。 PCA 会毫不犹豫地选 x1——方差大嘛。可投到 x1 上,两类彻底糊在一起,什么都分不出来。 它优化的是「投影后散得开」,不是「投影后分得开」。 散得开和分得开是两件事。 LDA 换了个目标:找一个方向,让投影之后「类与类之间的距离」尽量大,同时「类内部的散布」尽量小。 这两个要求合起来就是所谓的Fisher 判据:类间散度除以类内散度,越大越好。 这个比值的妙处在于它是尺度无关的:方向向量乘 10 倍,分子分母同时乘 100,比值不变。 所以 LDA 只需要找方向,不用管长度。
二、两个散度矩阵
类内散度 Sw:把每一类的点减去自己的中心,平方求和,再把各类加起来。
它衡量「同一类内部有多散」。这个数越小越好。
类间散度 Sb:把每一类的中心减去全体中心,按类的大小加权,平方求和。
它衡量「各类中心彼此隔得多远」。这个数越大越好。
投影到方向 w 上之后,类内散度变成 wᵀSw w,类间散度变成 wᵀSb w,Fisher 判据就是这两个二次型之比。
求它的最大值,归结成解一个广义特征值问题:Sw 的逆乘 Sb 的最大特征向量,就是最佳方向。
这个解有个很直观的名字叫白化再找方向:先乘 Sw 的逆,等于把数据「压扁」到各类内部一样散,
然后在压扁后的空间里找类间散度最大的方向。先消掉「谁本来就散」,再比「谁分得开」。
工程上有个细节:Sw 可能是奇异的(特征数多于样本数时必然如此),直接求逆会炸。
所以代码里用的是伪逆 pinv。
这也是 LDA 在小样本高维数据上常要先做一次 PCA 的原因——先把维度降到 Sw 可逆,再做 LDA。
三、同一份数据,两个方向
Demo 造了两类点,每类 150 个。 关键设计:x1 方向上两类的标准差都是 2.5(散得厉害),中心只错开 1; x2 方向上标准差只有 0.45(挤得紧),中心差 3。 一句话:x1 「散得厉害但分不开」, x2 「挤得紧但分得开」。 结果很清楚:PCA 的方向是 (−0.974, −0.226),基本落在 x1 上; LDA 的方向是 (+0.016, −1.000),几乎是垂直的。 同一个数据集,两种「好方向」的定义,选出两个完全不同的方向。 投影到一维之后差距更明显:PCA 的分离度 0.6866(小于 1,两团重叠),LDA 的 6.7165。 9.8 倍。 这就是「知道有类」和「不知道有类」的区别。 但要注意:LDA 并不是「更好的 PCA」。 它俩优化的东西不一样。 如果下游任务是「压缩存储」而不是「分类」, PCA 才是对的——LDA 会为了分开类而丢掉大量与分类无关的变化,那些变化在重建时是必需的。
四、它的硬上限:类数减一
LDA 最多能把数据降到「类别数 − 1」维。 两类最多降到 1 维,三类最多 2 维, 十类最多 9 维——再往上找不出方向了。 为什么?因为类间散度矩阵 Sb 的秩最多是「类数 − 1」。 直观理解:k 个类的中心,减去全体中心之后,这些向量加起来等于 0(加权平均), 所以它们最多只有 k − 1 个是独立的。Sb 的秩就是这个独立方向数。 这个上限在小类别数时很要命。做一个 3 类的可视化,LDA 最多给你 2 维,正好能画; 做一个 100 类的细粒度分类,LDA 最多 99 维, 而原始特征可能有几万维——中间那一大段压缩,LDA 帮不上忙。 这也是实践中常见的组合拳: 先用 PCA 把几万维降到几百维(无监督,保信息),再用 LDA 降到几十维(有监督,保可分性)。 两步各干各擅长的事。
五、两个 LDA 不是一回事
这一节的 LDA 是 Linear Discriminant Analysis,中文叫线性判别分析,有监督的降维方法。 它的亲戚还有 QDA(二次判别分析),区别是假设各类协方差不同。 另一个常被叫 LDA 的是 Latent Dirichlet Allocation,中文叫潜在狄利克雷分配, 无监督的主题模型,用来从文档里抽主题。 它和上一节 LSA 是同一个赛道的东西,只是用了概率生成模型那套语言。 两个东西除了三个字母一样,没有任何关系。 一个是降维,一个是主题模型; 一个要标签,一个不要标签。读论文、看文档时看到 LDA,先看上下文判断是哪个。 顺便说,这一类同名不同义的坑还有几个: PCA 和「主成分回归」不是一回事;「逻辑回归」是分类不是回归; 「朴素贝叶斯」的「朴素」是「假设特征独立」的意思,不是「简单」。 术语这东西, 撞车比想象中常见。
六、动手 Demo:PCA 选散得最开的方向,LDA 选分得最开的方向
两类点各 150 个。x1 方向上标准差 2.5、中心只错开 1;x2 方向上标准差 0.45、中心差 3。 换句话说:x1 上散得厉害但分不开,x2 上挤得紧但分得开。 这个设计就是为了让两个方法分道扬镳。 代码做两件事:算类内散度 Sw 和类间散度 Sb,取伪逆乘 Sb 的最大特征向量当 LDA 方向; 再对协方差矩阵做特征值分解,取最大特征向量当 PCA 方向。两条路都不需要迭代。
import numpy as np
m0, m1 = X[y == 0].mean(axis=0), X[y == 1].mean(axis=0)
Sw = np.zeros((2, 2)) # 类内散度:每类自己散得多开
for c in (0, 1):
Xc = X[y == c] - X[y == c].mean(axis=0)
Sw += Xc.T @ Xc
Sb = n * np.outer(m0 - X.mean(axis=0), m0 - X.mean(axis=0)) \
+ n * np.outer(m1 - X.mean(axis=0), m1 - X.mean(axis=0))
# 让「类间散度 / 类内散度」最大的方向,就是 Sw 逆乘 Sb 的最大特征向量
ev, evec = np.linalg.eig(np.linalg.pinv(Sw) @ Sb)
w_lda = np.real(evec[:, np.argmax(np.real(ev))])
# 对照:PCA 只找方差最大的方向,完全不看 y
C = np.cov((X - X.mean(axis=0)).T)
ev2, evec2 = np.linalg.eigh(C)
w_pca = evec2[:, np.argmax(ev2)]
实跑输出:
--------------------------------------------------------------------
LDA:让两类投影之后离得最远
--------------------------------------------------------------------
造两类点,每类 150 个。
**关键设计:两类在 x1 方向上拉得很长(标准差 2.5)、中心只错开 1,**
**在 x2 方向上分得很开(中心差 3、标准差只有 0.45)。**
也就是说,x1 方向「散得厉害但分不开」,x2 方向「挤得紧但分得开」。
【一】两个方向各是什么
方法 方向向量 它优化什么
----------------------------------------------------
PCA (-0.974, -0.226) 投影后方差最大
LDA (+0.016, -1.000) 类间散度除以类内散度最大
PCA 的方向基本落在 x1 上——因为 x1 方向上两类的方差大得多,**方差大的方向,PCA 就选它。**
LDA 的方向几乎是垂直的——因为 x2 方向上两类分得开。
**同一个数据集,两种「好方向」的定义,选出两个方向。**
【二】投影到一维之后,两类分得开吗
方法 类 0 均值 类 1 均值 分离度
----------------------------------------
PCA -0.2458 -1.8805 0.6866
LDA 0.0280 -2.9631 6.7165
分离度是「两类中心的距离」除以「两类标准差」——越大越好,小于 1 基本就是两团糊在一起。
**PCA 只有 0.69,糊成一团;LDA 有 6.72,隔得干干净净。倍数上差了 9.8 倍。**
原因很直白:PCA 完全不知道有「类别」这回事,它只找方差大的方向。
【三】所以它和 LSA 那个 LDA 不是一回事
这一节的 LDA 是 **Linear Discriminant Analysis(线性判别分析)**,**有监督**
的降维方法——它用类别标签算类间散度和类内散度。
另一个常被叫 LDA 的是 **Latent Dirichlet Allocation(潜在狄利克雷分配)**,**无监督**
的主题模型,用来从文档里抽主题。**两个东西除了缩写一样,没有任何关系。**
读论文时看到 LDA 要先看上下文。
【四】什么时候用 LDA,什么时候用 PCA
场景 选哪个 理由
--------------------------------------------------------------------------
有标签,想降维后好分类 LDA 它专门优化类间可分性
没标签,想压缩或可视化 PCA 不需要标签
想找回数据的主要变化方向 PCA 它保的是方差,不是可分性
类别数多于特征数时 LDA 最多降到类数减一维 这是它的硬限制
**LDA 的降维上限是「类别数 − 1」。**
因为类间散度矩阵的秩最多就是这么多,再多找不出方向了。
三类数据最多降到两维——这也是为什么做可视化时,LDA 画出来常常正好是二维。
方向表看一眼就懂。PCA 是 (−0.974, −0.226),几乎躺在 x1 上;LDA 是 (+0.016, −1.000),几乎垂直。 同一个数据集,两个方向几乎垂直。 分离度表才是判分的地方:0.6866 对 6.7165。小于 1 意味着两团重叠得很厉害, 6.7 意味着两团中心隔了六七个标准差。差了 9.8 倍。 注意 LDA 的分离度是负数方向算出来的。方向向量整体反号不影响分离度(因为取了绝对值), 所以「类 0 均值 0.028、类 1 均值 −2.963」和反过来写是一回事。符号不用纠结,看间距。 最后那张表是选型清单。有标签想分类就用 LDA,没标签想压缩就用 PCA,想找回主要变化方向还是 PCA。 没有「哪个更好」,只有「哪个目标对得上」。
30 秒实验
- 把两类的 x2 中心差从 3 改成 1.5,PCA 和 LDA 的分离度会变成多少?差距还在吗?
- 把 x1 的中心错开从 1 改成 3(两类在 x1 上也能分开),LDA 的方向会转到哪?
- 做三类的数据,用这份代码最多能降到几维?降到 2 维之后还能画图看吗?
常见误区
- 以为 LDA 是「更好的 PCA」。它俩优化的目标不同:PCA 保方差,LDA 保可分性。 下游是压缩或重建时用 LDA 会丢关键信息。先想清楚下游任务是什么。
- 在高维小样本上直接用 LDA。特征数超过样本数时 Sw 必然奇异,求逆会炸或给出垃圾方向。 先做 PCA 降维,或者用收缩估计。
- 把两个 LDA 搞混。线性判别分析(降维,要标签)和潜在狄利克雷分配(主题模型, 不要标签)是两回事。看到 LDA 先看上下文。
自测三问(点开对答案)
1. Fisher 判据优化的是什么比值?为什么它和尺度无关? —— 类间散度除以类内散度(投影之后)。 方向向量乘任意倍数,分子分母同时乘这个倍数的平方,比值不变,所以只需要找方向不用管长度。 2. 为什么 LDA 最多只能降到「类数 − 1」维? —— 因为类间散度矩阵的秩最多是类数减一:k 个类的中心减去全体中心后,这些向量加权和为 0, 最多 k − 1 个线性无关。秩就是能找出的方向数上限。 3. 什么情况下该用 PCA 而不是 LDA? —— 没有标签的时候(LDA 用不了),或者下游任务是压缩、重建、可视化而不是分类的时候。 PCA 保住的是总方差,这对重建更有利。3.1 到 3.4 四个算法都在「换坐标」。 从 3.5 节开始换一类问题:数据是几团拼起来的,怎么把团找出来。 先看最出名的 k-means。
- ☐ (本节完,下一节 3.5 算法 14:k-means 算法)