☰
LDA线性判别分析:分类聚团式降维,你该了解的PCA替代方案
2026/10/19 5:12:04 网站建设 项目流程

1. 为什么说到降维,大家总是先想起PCA而忘了LDA

1.1 我那次用PCA做分类预处理栽的跟头

先说一个我自己的经历。某次做一个图像分类的小项目,特征工程做完之后特征维度到了好几百,模型训练慢不说,过拟合也明显。当时脑子里的第一反应就是"降维嘛,上PCA"。于是二话不说把特征降到50维,丢给分类器跑了一轮。结果挺打脸的:准确率比降维之前还低了两三个点,更诡异的是,把降维后的特征可视化出来,三个类别在二维平面里挤成一团,几乎看不出结构。

后来一个做统计出身的朋友提醒了一句:"你下一步要做分类,怎么用了个不管标签死活的无监督降维?"这句话让我意识到,降维不是只有PCA这一条路。对于"降完维之后还要做分类"的场景,应该优先考虑今天这篇的主角——LDA线性判别分析。它和PCA最大的区别,从名字就能看出来:PCA只管"方差最大",LDA管的则是"分类聚团"。

很多教程喜欢把LDA放在PCA后面当对照组讲,但实际项目里用到LDA的频率并不低,尤其是做特征压缩、数据可视化、分类前预处理这几件事的时候。如果你和我一样,曾经在"降维"和"分类"之间走过弯路,这篇文章应该能帮你把思路理清楚。

1.2 降维这件事有两种完全不同的目的

想把LDA理解到位,先得把"降维目的"这件事掰开。同样是降维,PCA和LDA看起来都是把高维数据投影到低维空间,但它们的优化目标和适用场景几乎相反。

PCA做的是无监督降维,它完全不看数据标签,只盯着样本本身的方差结构,找到那些能最大限度保留原始数据散布的方向。PCA的理想结果是:投影之后样本之间的整体距离尽量拉大,信息损失尽量小。它适合做特征压缩、去相关、可视化探索,但它不保证降维后的空间对分类友好。两个类别在原始空间里可能本来分得开,PCA却可能因为"整体方差最大"这个目标,把一个对分类极有区分度的方向给压缩掉了,我上面那个项目就是典型例子。

LDA做的是有监督降维,它需要知道每个样本属于哪一类。LDA的目标非常明确:找一个投影方向,让不同类别的样本在这个方向上尽可能分开,同时让同类别的样本尽可能聚拢。用一个形象的比喻就是——一屋子人乱糟糟站着,PCA想的是"怎么把大家的活动范围摊得最开",LDA想的是"怎么给每个人找个位置,让同一家人挨在一起、不同家庭离得远远的"。

所以判断标准很简单:如果你的下游任务是分类、识别、检索这类需要"区分度"的场景,先试LDA而不是PCA。这也是LDA常被称为"Fisher线性判别"的原因——它本质是在做判别,降维只是它的副产品。

2. LDA的"分类聚团"直觉:把散点图当成一群人要合影

2.1 核心思想就两句话:类内紧凑、类间疏远

LDA的数学推导看起来有点绕,但背后直觉极其简单。设我们有一堆二维平面上的点,分属三个类别,现在想把它们投影到一条直线上,也就是降成一维。问题来了:往哪个方向投影最好?

先看看两个极端方向。如果投影方向选得不好,比如恰好选了和类别分布"垂直"的方向,三类样本投到一维之后会完全重叠在一起,什么信息都看不出来。如果选了一个"斜着"的方向,可能某一类分开了,另外两类还缠在一起,效果也不理想。LDA要找的是那个"最优方向",它同时满足两个条件:

  • 类内距离小:同类别样本投影之后尽量挤在一起,别散成一盘沙。
  • 类间距离大:不同类别的中心点投影之后尽量离得远,别互相叠着。

这两个条件合起来,就是标题里说的"分类聚团"思维。类内紧凑保证分类器在低维空间里不容易混淆同类样本,类间疏远保证不同类别之间有足够间隙,分类边界想怎么划都行。

一个特别容易误解的地方是:LDA并不是只关心类间距离,如果只看类间距离,投影方向最远的那条线往往会让每一类内部也极度分散,分类边界依然很难找。LDA真正的目标是一个比值最大化——类间距离和类内离散度的比值,而不是单独追求任何一个。

2.2 Fisher线性判别里的那个经典比值

这个比值最早来自Fisher在1936年提出的线性判别思想,公式写出来是这样的:最大化 ( J(w) = \frac{w^T S_b w}{w^T S_w w} )。

我先把符号用人话翻译一遍。( w ) 是我们要求的投影方向(一个向量),( S_b ) 是类间散度矩阵,度量不同类别中心相对全局中心的分散程度;( S_w ) 是类内散度矩阵,度量每个类别内部样本相对自己类别中心的分散程度。( J(w) ) 的含义就是:投影之后,类间分散程度与类内分散程度的比值。

为什么要最大化这个比值?举个例子,A方向投影后类间距离是10,类内标准差是2,比值是5;B方向投影后类间距离是12,但类内标准差是4,比值只有3。虽然B方向类间距离更大,但类别内部被拉扯得太厉害,边界处两类样本反而容易交叉,所以A方向更优。比值最大化本质上是在找一个折中点:距离要够大,但聚类不能散架。这就是Fisher判别的精髓。

如果你不想深究矩阵推导,先记住这个直觉就行——LDA找到的方向,是让"组间差异除以组内差异"最大的方向。这个比值也是LDA和PCA之间最本质的分水岭:PCA最大化的是整体方差,LDA最大化的是可分性。

3. LDA降维的数学骨架(科普版推演)

3.1 散度矩阵到底在算什么

很多人在这一步被劝退,其实散度矩阵没那么可怕。我们先从一维类比开始。假设现在只看一个特征,想衡量"类内紧凑程度",最自然的做法是算每个类别内部样本到该类中心距离的平方和。把所有类的这个值加起来,就是总体类内离散度。放在多维空间里,这个"距离平方和"就变成向量外积的累加,也就是 ( S_w )。

同理,类间散度 ( S_b ) 衡量的是每个类别的中心点相对于全局中心的偏离程度,也是用向量外积累加得到的。两个矩阵都是对称半正定的,它们把"分散程度"用矩阵的形式编码了起来。矩阵对一个向量 ( w ) 做二次型 ( w^T S w ),本质上就是在算:所有样本沿 ( w ) 方向投影之后,离散程度的加权总和。

所以 ( J(w) ) 这个式子并不是从天而降的公式,它就是在回答一个问题:沿着某个方向看,类别间差异相对类别内差异有多大?矩阵只是把"方向"和"离散度"之间的函数关系包装得更紧凑而已。

3.2 特征值分解出来的为什么是"判别方向"

最大化 ( J(w) ) 这个问题,标准的解法是对 ( S_w^{-1} S_b ) 做特征值分解。这里有一个很优雅的数学结论:当 ( S_w ) 可逆时,使比值最大的方向 ( w ) 就是 ( S_w^{-1} S_b ) 最大的特征值对应的特征向量。

为什么特征值分解能同时兼顾"类间大、类内小"?关键在于 ( S_w^{-1} ) 这个逆矩阵的几何意义。它相当于在做一次"白化"变换:先沿着类内离散度大的方向把数据"压扁",再在这个修正过的空间里找类间散度最大的方向。换句话说,LDA首先惩罚了那些类内已经很散的方向,然后再在剩下"状态良好"的方向里找区分度。这就是它比单独看类间距离更稳健的数学原因。

如果你只需要降维到 ( k ) 维,就取前 ( k ) 个最大特征值对应的特征向量组成投影矩阵。实际使用中可以不用自己手写这些矩阵运算,sklearn里的LinearDiscriminantAnalysis封裝得很好,但理解背后的特征值逻辑对解读结果、判断是否适用LDA都很有帮助。

3.3 最多只能降到类别数减一

这是LDA一个非常容易踩坑的硬性限制:LDA降维后最多只能得到 ( C-1 ) 个维度,其中 ( C ) 是类别数。比如做二分类,LDA最多只能降到一维;五分类最多降到四维。原因是 ( S_b ) 这个矩阵的秩最多是 ( C-1 ),它描述的是类别中心之间的差异,而 ( C ) 个中心之间的自由度天然只有 ( C-1 )。

这意味着什么?如果你有10个类,原始特征有100维,LDA最多帮你降到9维。这和PCA完全不同,PCA最多能降到特征维度数。很多第一次用LDA的人,以为它和PCA一样想降几维降几维,结果sklearn直接报错或者返回的维度比自己设的小,一脸懵——其实这是LDA的数学性质决定的,不是bug。

在实操里,这个限制也不完全是坏事。类别数通常不会太多,LDA把高维特征压到 ( C-1 ) 维之后再配分类器,往往既能大幅降低维度、缓解过拟合,又能保留类别可分性。比如一个10分类问题,1000维特征压到9维,压缩比非常可观。

4. 跑通一个LDA降维实验(Python示例)

4.1 人造三类数据集准备

理论讲再多,不如跑一次实验来得直观。我这边用Python的sklearn写个完整示例,方便你直接复现。

先造一个三类、三特征的数据集。为了让效果明显,我故意让每个类别的均值中心在三维空间里分得比较开,但类内又有一定噪声,这样既贴近真实场景,又方便观察LDA的效果。

import numpy as np import matplotlib.pyplot as plt from sklearn.datasets import make_classification from sklearn.discriminant_analysis import LinearDiscriminantAnalysis from sklearn.model_selection import train_test_split from sklearn.ensemble import RandomForestClassifier from sklearn.metrics import accuracy_score # 生成三类、三维特征、共600个样本的数据集 X, y = make_classification( n_samples=600, n_features=3, n_informative=3, n_redundant=0, n_classes=3, n_clusters_per_class=1, class_sep=1.8, random_state=42 ) X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.3, random_state=42 ) print(X.shape) # (600, 3)

make_classification是sklearn里很方便的合成数据工具,可以控制类别数、信息特征数、类别间隔等参数。我这里特意设了n_informative=3,让三个特征都携带分类信息,方便后续观察LDA降维是否真的能保留区分度。

4.2 使用sklearn中的LDA进行降维

接下来直接调用LinearDiscriminantAnalysis。三分类情况下LDA最多能降维到 ( 3-1=2 ) 维,我们正好降到2维,然后做可视化。

# 初始化LDA,指定降到2维 lda = LinearDiscriminantAnalysis(n_components=2) X_train_lda = lda.fit_transform(X_train, y_train) X_test_lda = lda.transform(X_test) print("降维后训练集形状:", X_train_lda.shape) # (420, 2) print("两个判别方向解释的类间方差比例:", lda.explained_variance_ratio_)

输出中会有explained_variance_ratio_这个属性,它表示每个判别方向承载的类间散度占比。比如出现[0.85, 0.15],意味着第一个判别方向已经解释了85%的类间差异,信息非常集中。这个值对判断"降到几维合适"很有参考意义。

这里有个使用细节值得注意:fit_transform和transform必须分开用,先在训练集上拟合,再用同样的投影矩阵变换测试集。如果直接把测试集丢进去fit_transform,会让测试集的信息泄漏到训练过程里,评估结果会虚高。

4.3 降维后可视化与分类效果对比

把降维后的数据画出来,你能非常直观地看到"分类聚团"的效果:

plt.figure(figsize=(12, 5)) plt.subplot(1, 2, 1) scatter0 = plt.scatter(X_train[y_train == 0][:, 0], X_train[y_train == 0][:, 1], c='skyblue', label='class 0', alpha=0.7, edgecolors='k') scatter1 = plt.scatter(X_train[y_train == 1][:, 0], X_train[y_train == 1][:, 1], c='salmon', label='class 1', alpha=0.7, edgecolors='k') scatter2 = plt.scatter(X_train[y_train == 2][:, 0], X_train[y_train == 2][:, 1], c='mediumseagreen', label='class 2', alpha=0.7, edgecolors='k') plt.title('Original Feature Space (first two dims)') plt.legend() plt.subplot(1, 2, 2) plt.scatter(X_train_lda[y_train == 0][:, 0], X_train_lda[y_train == 0][:, 1], c='skyblue', label='class 0', alpha=0.7, edgecolors='k') plt.scatter(X_train_lda[y_train == 1][:, 0], X_train_lda[y_train == 1][:, 1], c='salmon', label='class 1', alpha=0.7, edgecolors='k') plt.scatter(X_train_lda[y_train == 2][:, 0], X_train_lda[y_train == 2][:, 1], c='mediumseagreen', label='class 2', alpha=0.7, edgecolors='k') plt.title('After LDA (2D)') plt.legend() plt.tight_layout() plt.show()

视觉效果通常是:原始三维特征中随便挑两个维度画,类别之间可能有重叠;LDA降维后的二维图里,三个类别会像三团云一样明显分开,边界干净很多。这也是LDA作为"可解释降维"手段的价值——投影方向时刻在往"好分类"的方向上靠。

为了量化效果,我再跑一个对比实验:分别在"原始特征"和"LDA降维后特征"上训练相同的随机森林分类器。

clf_raw = RandomForestClassifier(n_estimators=200, random_state=42) clf_raw.fit(X_train, y_train) acc_raw = accuracy_score(y_test, clf_raw.predict(X_test)) clf_lda = RandomForestClassifier(n_estimators=200, random_state=42) clf_lda.fit(X_train_lda, y_train) acc_lda = accuracy_score(y_test, clf_lda.predict(X_test_lda)) print(f"原始特征准确率: {acc_raw:.4f}") print(f"LDA降维后准确率: {acc_lda:.4f}")

在我用这个参数跑出来的结果里,LDA降维后的准确率往往比原始3维特征略高或者持平,绝不会出现PCA那种明显掉点的情形。如果原始特征维度更高、噪声更大,LDA的优势会更突出——因为它降维的同时等于在帮你做了一次"针对分类任务的去噪"。

5. LDA的适用边界与常见误区

5.1 数据服从高斯分布且各类协方差相近

LDA虽然好用,但它并非在所有场景下都是最优选择。它有一个隐含假设:每个类别的数据近似服从高斯分布,并且各类别的协方差矩阵大致相同。在这个假设下,贝叶斯最优分类器会退化成一个线性决策边界,LDA恰好是这个边界对应的投影。

如果各类别协方差差异很大,比如一类数据很"瘦长"、另一类很"矮胖",LDA找出来的线性方向可能很难把两类干净地分开。这时候可以考虑QDA(二次判别分析),它允许各类协方差不同,决策边界是二次曲线,拟合能力更强但更需要充足样本。

一个常见误区是:LDA名字里带"线性",所以以为它只能处理线性可分的数据。其实LDA在处理非线性数据时同样能给出一个有意义的投影方向,只是它无法保证在这个方向下类别彻底分离。对于明显非线性的数据(比如环形分布、螺旋分布),更合适的是先做核技巧(Kernel LDA)或者直接用深度特征加上Metric Learning。LDA不是万能的,但作为线性基准非常可靠。

5.2 样本量远小于特征数时的坑

LDA求解需要 ( S_w ) 可逆,而 ( S_w ) 的维度等于特征维度。当特征数量远大于样本数量时(也就是所谓的p >> n问题),( S_w ) 往往是奇异矩阵,求逆根本无从谈起。这就是典型的"小样本问题",在高维生物数据、文本数据里非常常见。

应对策略有几个:第一,先用PCA做一个初步降维,把特征压到样本量以内,再跑LDA;第二,对 ( S_w ) 做正则化,sklearn里LinearDiscriminantAnalysis提供了shrinkage参数,设置为一个0到1之间的小数即可对类内散度矩阵的对角线做收缩,从而让它可逆;第三,用解( S_w^{-1} S_b )的替代解法,比如基于广义特征值分解,sklearn内部在svd求解器下就是这么处理的。

实话说,在我处理过的几个高维小样本数据集上,shrinkage的作用肉眼可见。比如一组数据原始维度5000、每类只有30个样本,直接跑LDA会崩或者结果极不稳定,开了shrinkage之后不仅稳定,分类效果也明显提升。遇到类似场景,先试试这个参数,别急着换算法。

5.3 LDA与PCA的选型对比表

我把两者的关键差异整理成一张表,平时做选型的时候可以直接参考:

对比维度PCALDA
监督/无监督无监督,不依赖标签有监督,依赖标签
优化目标最大化投影后方差最大化类间/类内散度比值
类别信息完全忽略核心依赖
下游任务压缩、可视化、去相关分类前降维、特征判别
降维上限可降到特征维数最多 ( C-1 ) 维
适用假定无特殊分布假定类别高斯分布、协方差相近
小样本高维一般可用需要正则化或先PCA
非线性数据需核方法(Kernel PCA)需核方法(Kernel LDA)

特别强调一下:PCA和LDA不是互斥关系,实践中经常组合使用。先跑PCA降低维度到一定程度,再跑LDA强化可分性,是处理高维数据的高频套路。我见过不少比赛方案就是这么干的,效果比单用一个要稳。顺序一定是先PCA后LDA,反过来不行——LDA已经把维度压到( C-1 )了,再用无监督的PCA去压缩这个判别空间,意义不大。

6. 我在实际项目中用LDA的一些体会

这个部分谈不上什么宏大结论,就是分享几个我实打实用过的经验。

第一,LDA非常适合做"降维可视化+后续建模"的双重任务。有一次做一个四分类的文本主题判别任务,原始词频特征上完TF-IDF之后维度接近8000。我先是PCA降到50维,再在这个基础上跑LDA降到3维,然后直接用3维特征训练随机森林。模型效果比直接用8000维TF-IDF还好了将近两个百分点,训练时间从两分钟缩到几秒。更让我意外的是,把3维投影特征画在三维图里,四个类别的样本形成了非常清晰的四团,连非技术的同事看了图都能理解模型在"看到"什么。这种"可解释性红利"是LDA相比纯黑盒降维方法最容易被忽视的价值。

第二,如果你想把这个思路再往前推一步,可以试试在LDA投影空间里构建分类器而不是回到原始空间。因为LDA的投影方向本身就是按"最优判别"来设计的,在这个空间里哪怕用最简单的最近邻分类器,效果也经常能和原始高维空间里调过参的复杂模型打平。做基线模型或者快速验证概念的时候,这条路相当省事。我现在的习惯是:拿到一个分类任务,先花五分钟用LDA降个维、跑个最近邻基线,再决定要不要上复杂模型——这个基线在大多数时候都出乎意料地能打。

第三,关于"到底该降多少维"这个问题,我的经验是看explained_variance_ratio_的累计曲线。如果前两个判别方向已经累计解释了90%以上的类间散度,说明绝大多数判别信息都被保留了,再增加维度收益很小;反过来,如果前几个方向只解释了50%,那不妨保留到( C-1 )维上限,或者考虑数据本身是否适合LDA。

最后想多说一句:LDA不是那种"一招鲜吃遍天"的算法,它和PCA的关系更像是"分类视角"和"重构视角"的区别。选哪个,取决于你降维之后要干什么。只要记住"分类聚团"这个思维——让同类的更近、异类的更远——你在绝大多数分类前预处理任务里都能做出比盲目套PCA更好的决定。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询