LDA(Linear Discriminant Analysis,线性判别分析),是一种有监督的降维和分类方法。它和 PCA 都是线性降维,但核心区别是:PCA 不看标签,LDA 看标签。
它属于你之前看的组件列表里(特征工程组件 -> Python特征工程组件 -> LDA)的核心功能。下面我从概念、原理、代码实现、典型场景几个方面来讲。
一、LDA 是做什么的?
LDA 有两个用途:
降维:把高维数据投影到低维空间,同时最大化类间距离、最小化类内距离。
分类:直接用 LDA 做分类器(sklearn 的
LinearDiscriminantAnalysis就支持)。
核心目标
投影后,同类样本尽量聚在一起,不同类样本尽量分开。
二、LDA 的核心思想
直观理解
想象两类数据(红点、蓝点)在二维平面上:
PCA:找方差最大的方向,不管红蓝。
LDA:找一个方向,让红点投影后挤在一起,蓝点也挤在一起,但红蓝之间离得远。
用一句话概括:
LDA 找的是"最能区分类别"的方向,PCA 找的是"最能代表数据分布"的方向。
数学目标
LDA 要最大化:
J(w)=wTSBwwTSWwJ(w)=wTSWwwTSBw
其中:
SBSB:类间散度矩阵(Between-class scatter),衡量不同类中心的距离。
SWSW:类内散度矩阵(Within-class scatter),衡量同类样本的分散程度。
目标:让分子(类间距离)大,分母(类内距离)小。
求解方法:对 SW−1SBSW−1SB 做特征值分解,取最大的 k 个特征值对应的特征向量。
降维后的维度上限
LDA 降维后的维度最多是类别数 - 1。
二分类:最多降到1 维。
三分类:最多降到2 维。
十分类:最多降到9 维。
这是 LDA 的硬性限制,因为类间散度矩阵 SBSB 的秩最多是类别数 - 1。
三、LDA vs PCA
| 维度 | PCA | LDA |
|---|---|---|
| 监督性 | 无监督 | 有监督 |
| 目标 | 方差最大 | 类间大、类内小 |
| 是否用标签 | 不用 | 用 |
| 降维上限 | 特征数 | 类别数 - 1 |
| 适用场景 | 降维、去噪、可视化 | 分类、有标签降维 |
| 新特征关系 | 不相关 | 不相关 |
| 分布假设 | 无 | 近似正态、同类协方差相同 |
一句话:PCA 是"无监督的降维",LDA 是"有监督的降维 + 分类"。
四、代码实现
1. 基本降维
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis from sklearn.datasets import load_iris # 加载鸢尾花数据(3类,4个特征) iris = load_iris() X, y = iris.data, iris.target print("原始形状:", X.shape) # (150, 4) # LDA 降到 2 维(3类最多降到2维) lda = LinearDiscriminantAnalysis(n_components=2) X_lda = lda.fit_transform(X, y) print("降维后形状:", X_lda.shape) # (150, 2) print("解释方差比例:", lda.explained_variance_ratio_)注意:LDA 的fit需要传入y(标签),这是和 PCA 最大的区别。
2. 可视化
import matplotlib.pyplot as plt plt.figure(figsize=(8, 6)) colors = ['red', 'green', 'blue'] for i, color in enumerate(colors): plt.scatter(X_lda[y == i, 0], X_lda[y == i, 1], c=color, label=iris.target_names[i], alpha=0.7) plt.xlabel('LD1') plt.ylabel('LD2') plt.title('LDA 降维可视化(鸢尾花)') plt.legend() plt.show()三类样本在 LD1/LD2 平面上分得很开。
3. LDA 作为分类器
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis from sklearn.model_selection import train_test_split from sklearn.metrics import accuracy_score X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.3, random_state=42, stratify=y ) # 直接用 LDA 做分类 lda_clf = LinearDiscriminantAnalysis() lda_clf.fit(X_train, y_train) y_pred = lda_clf.predict(X_test) print("LDA 分类准确率:", accuracy_score(y_test, y_pred))LDA 本身就是分类器,不需要先降维再分类。
4. 降维 + 分类(Pipeline)
from sklearn.pipeline import Pipeline from sklearn.discriminant_analysis import LinearDiscriminantAnalysis from sklearn.linear_model import LogisticRegression pipe = Pipeline([ ('lda', LinearDiscriminantAnalysis(n_components=2)), # 先降到2维 ('clf', LogisticRegression()) # 再分类 ]) pipe.fit(X_train, y_train) print("Pipeline 准确率:", pipe.score(X_test, y_test))5. 二分类问题
python
from sklearn.datasets import make_classification from sklearn.discriminant_analysis import LinearDiscriminantAnalysis # 二分类数据 X, y = make_classification(n_samples=200, n_features=10, n_classes=2, random_state=42) # 二分类最多降到 1 维 lda = LinearDiscriminantAnalysis(n_components=1) X_lda = lda.fit_transform(X, y) print("降维后形状:", X_lda.shape) # (200, 1)6. 使用solver参数
solver决定求解方法:
| solver | 说明 | 适用场景 |
|---|---|---|
'svd' | 奇异值分解(默认) | 通用,不需要计算协方差矩阵 |
'lsqr' | 最小二乘 | 只用于分类 |
'eigen' | 特征值分解 | 需要shrinkage参数 |
'svd' | 推荐 | 默认,稳定 |
python
# 用 shrinkage 提升稳定性(高维小样本) lda = LinearDiscriminantAnalysis(solver='eigen', shrinkage='auto')
shrinkage可选:
None:不收缩'auto':自动(Ledoit-Wolf 估计)0~1 之间的浮点数:手动指定
7. 处理新数据(transform)
python
X_new = X_test[:5] X_new_lda = lda.transform(X_new) print(X_new_lda.shape)
五、LDA 的重要属性
| 属性 | 说明 |
|---|---|
coef_ | 分类器的权重系数 |
intercept_ | 分类器的截距 |
explained_variance_ratio_ | 各判别方向的解释方差比例 |
means_ | 每个类别的均值 |
priors_ | 每个类别的先验概率 |
scalings_ | 判别方向的缩放(特征向量) |
classes_ | 类别标签 |
六、LDA 的优缺点
优点
有监督:利用标签信息,降维后分类效果好。
简单快速:计算成本低,适合大规模数据。
可解释性较好:判别方向有明确含义。
自带分类:不需要额外模型。
降维上限明确:类别数 - 1,避免维度爆炸。
缺点
假设强:假设数据近似正态、各类协方差相同。实际数据可能不满足。
降维上限:最多降到 类别数 - 1 维,类别少时受限。
对异常值敏感:均值和协方差受异常值影响。
线性:只能找线性判别边界,非线性关系要用 QDA、KernelLDA。
小样本问题:特征数 > 样本数时,SWSW 不可逆,需要 shrinkage 或正则化。
七、LDA 的变体
| 变体 | 说明 |
|---|---|
| QDA(二次判别分析) | 允许各类协方差不同,边界是二次曲线 |
| KernelLDA | 用核函数处理非线性 |
| Regularized LDA | 加正则化,解决小样本问题 |
| Sparse LDA | 加 L1 正则,做稀疏特征选择 |
| Flexible LDA | 用样条等非线性变换 |
sklearn 只提供了 LDA 和 QDA:
from sklearn.discriminant_analysis import QuadraticDiscriminantAnalysis qda = QuadraticDiscriminantAnalysis() qda.fit(X_train, y_train) print("QDA 准确率:", qda.score(X_test, y_test))八、典型应用场景
| 场景 | 说明 |
|---|---|
| 人脸识别 | Fisherfaces 就是 LDA |
| 文本分类 | 降维 + 分类 |
| 医学诊断 | 疾病分类 |
| 信用评分 | 好坏客户分类 |
| 模式识别 | 通用分类任务 |
| 数据可视化 | 降到 2-3 维画图 |
| 特征提取 | 有标签数据的降维 |
九、关键提醒
LDA 需要标签:
fit(X, y),这是和 PCA 最大的区别。降维上限 = 类别数 - 1:二分类最多 1 维,三分类最多 2 维。
假设近似正态、协方差相同:不满足时考虑 QDA 或 KernelLDA。
对异常值敏感:先做异常值处理。
小样本问题:特征数 > 样本数时,用
shrinkage='auto'。参数从训练集学:
fit只在训练集,测试集只transform,避免数据泄露。可先标准化:虽然 LDA 对尺度不如 PCA 敏感,但标准化通常有帮助。
和 PCA 结合:可以先用 PCA 降维去噪,再用 LDA。
十、总结
LDA = 有监督的线性降维 + 分类,目标是最大化类间距离、最小化类内距离。
核心思想:投影后同类聚集、异类分开。
sklearn 实现:
LinearDiscriminantAnalysis、QuadraticDiscriminantAnalysis。关键参数:
n_components、solver、shrinkage。重要限制:降维上限 = 类别数 - 1。
核心价值:有标签降维、自带分类、可解释性好。
主要代价:假设强、对异常值敏感、线性。
和 PCA 的区别:PCA 无监督看方差,LDA 有监督看类别区分度。
它和前面讲的 PCA、FastICA 都是特征变换方法,区别在于:
PCA:无监督,看方差。
FastICA:无监督,看独立性。
LDA:有监督,看类别区分度。