锋哥原创的Scikit-learn Python机器学习视频教程:
2026版 Scikit-learn Python机器学习 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili
课程介绍

本课程主要讲解基于Scikit-learn的Python机器学习知识,包括机器学习概述,特征工程(数据集,特征抽取,特征预处理,特征降维等),分类算法(K-临近算法,朴素贝叶斯算法,决策树等),回归与聚类算法(线性回归,欠拟合,逻辑回归与二分类,K-means算法)等。
Scikit-learn Python机器学习 - 特征降维 压缩数据 - 特征提取 - 线性判别分析 (LDA)
LDA是一种有监督的降维方法,旨在最大化类间距离,最小化类内距离。
线性判别分析(Linear Discriminant Analysis, LDA)是一种经典的有监督 学习算法,主要用于分类 和降维 。它的核心思想与主成分分析(PCA)不同:PCA追求的是数据方差最大化,是一种无监督的降维方法;而LDA追求的是最大化类间散度(类与类之间的距离)的同时最小化类内散度(同一类内的数据离散程度),即寻找能够最好地将不同类别区分开来的特征子空间。
1. 核心目标
给定数据集,LDA的目标是找到一个投影方向(对于多类问题则是投影平面),使得:
-
类间散度(Between-class scatter)最大:不同类别的投影点中心尽可能远离。
-
类内散度(Within-class scatter)最小:同一类别的投影点尽可能聚集。
通过优化这两个目标,LDA能使得投影后的数据具有最好的分类效果。
2.数学定义与推导
线性鉴别分析的基本思想是将高维的模式样本投影到最佳鉴别矢量空间,以达到抽取分类信息和压缩特征空间维数的效果,投影后保证模式样本在新的子空间有最大的类间距离和最小的类内距离,即模式在该空间中有最佳的可分离性。因此,它是一种有效的特征抽取方法。使用这种方法能够使投影后模式样本的类间散布矩阵最大,并且同时类内散布矩阵最小。就是说,它能够保证投影后模式样本在新的空间中有最小的类内距离和最大的类间距离,即模式在该空间中有最佳的可分离性。

在 scikit-learn
库中 LinearDiscriminantAnalysis
类来实现LDA。
在 sklearn.discriminant_analysis
模块中,LinearDiscriminantAnalysis
的构造函数如下:
LinearDiscriminantAnalysis(solver='svd',
shrinkage=None,
priors=None,
n_components=None,
store_covariance=False,
tol=0.0001,
covariance_estimator=None)
参数详解
solver
: str, {'svd', 'lsqr', 'eigen'}, default='svd'
求解器算法 。这是最重要的参数,它决定了LDA内部采用何种数学算法来求解,并且它会限制其他一些参数是否可用。
-
'svd' (奇异值分解):
-
原理: 不直接计算散度矩阵 S_w,而是通过SVD(奇异值分解)来求解。这是一种数值上最稳定、最精确的方法。
-
优点:
-
无需计算 S_w 和 S_b,节省内存,尤其适用于特征数量非常多(甚至多于样本数)的场景。
-
不会因为 S_w 是奇异矩阵(不可逆)而出现问题。
-
-
限制 : 不能使用
shrinkage
(收缩)参数。 -
适用场景 : 默认选择。在大多数情况下都是最佳选择,特别是当特征维数高或担心数值稳定性时。
-
-
'lsqr' (最小二乘解):
-
原理: 通过最小化平方误差来求解。此算法可以执行收缩。
-
优点 : 支持
shrinkage
。 -
要求 : 需要计算协方差矩阵,因此当
n_features
很大时可能效率不高。 -
适用场景 : 当你明确需要使用收缩,并且特征维度不是极高时。
-
-
'eigen' (特征值分解):
-
原理: 通过求解广义特征值问题 S_b w = \\lambda S_w w 来求解(即我们原理部分推导的方法)。此算法也可以执行收缩。
-
优点 : 支持
shrinkage
。 -
要求: 需要计算协方差矩阵,同样不适用于特征维度极高的场景。
-
适用场景 : 与
'lsqr'
类似,当你需要收缩且特征数不多时。'eigen'
和'lsqr'
的结果通常非常相似。
-
总结选择指南:
-
默认或特征数很多 ->
'svd'
-
需要收缩(Shrinkage) ->
'lsqr'
或'eigen'
shrinkage
: float or 'auto', default=None
收缩参数 。用于估计协方差矩阵的正则化方法,主要用于解决当样本数量少于特征数量时,S_w 矩阵奇异(不可逆) 的问题,或者改善协方差矩阵的估计。
-
原理: 收缩通过将类内散度矩阵 S_w 向一个对角矩阵(或单位矩阵)进行"缩小"来正则化它: \\hat{\\Sigma} = (1 - \\text{shrinkage}) \* S_w + \\text{shrinkage} \* \\sigma\^2 I
-
取值:
-
None
或0
: 不进行任何收缩。 -
'auto'
: 使用Ledoit-Wolf引理自动确定最优的收缩强度。这是非常实用的一个选项。 -
float
between 0 and 1: 手动指定固定的收缩强度。例如,0.5
表示一半是原始协方差,一半是对角矩阵。
-
-
依赖关系 : 仅当 solver 为 'lsqr' 或 'eigen' 时有效 。
'svd'
求解器不需要也不支持收缩。 -
适用场景 : 当训练样本数较少 、特征数较多 导致模型过拟合或 S_w 奇异时,设置
shrinkage='auto'
通常能显著提升模型的泛化能力。
priors
: array-like of shape (n_classes,), default=None
类的先验概率。
-
原理: 在贝叶斯框架下,LDA可以融入关于类别分布的先验知识。如果你知道你的数据中各类别的出现概率(例如,在医学诊断中,健康人群远多于患病人群),可以通过此参数指定。
-
取值 : 一个长度等于类别数的数组,数组元素之和应为1.0。例如,对于三分类问题,可以设置为
[0.3, 0.3, 0.4]
。 -
默认 None : 模型将直接从训练数据中计算每个类的先验概率,即
priors = np.bincount(y) / len(y)
。 -
影响: 这个参数会直接影响决策边界的位置。如果你设置的先验概率与数据中的真实分布差异很大,决策边界会向先验概率较小的类别方向移动。
n_components
: int, default=None
降维后希望保留的维度数。
-
原理 : LDA降维后的最大维度是
min(n_features, n_classes - 1)
。此参数用于指定最终保留的维度。 -
取值:
-
None
: 默认值,会自动设置为n_classes - 1
。 -
int
: 一个小于n_classes - 1
的整数。例如,对于4分类问题,最多可降到3维,你可以设置n_components=2
来只取前两个线性判别式。
-
-
注意 : 此参数主要用于降维 。即使你将其用作分类器,
transform
方法也会使用这个维度。
store_covariance
: bool, default=False
是否计算并存储每个类的协方差矩阵。
-
原理 : 为
True
时,模型拟合后会有covariance_
属性,它是一个数组,包含了每个类的协方差矩阵。 -
取值:
-
False
(默认): 不存储。节省内存。 -
True
: 存储。主要用于调试和可视化,或者你需要查看类的协方差结构时。
-
-
依赖关系 : 仅当
solver='svd'
时不可用,因为'svd'
求解器根本不计算协方差矩阵。
tol
: float, default=1e-4
用于秩估计的阈值。
-
原理 : 当
solver='svd'
时,用于判断矩阵秩的容差值。任何奇异值小于tol
的维度都会被丢弃。这是一个非常技术性的参数,通常不需要调整。 -
适用场景: 除非你非常了解数值线性代数,并且发现默认值导致了一些问题,否则保持默认即可。
covariance_estimator
: estimator, default=None
协方差估计器。
-
原理 : 这是一个实验性 参数(截至
scikit-learn
1.2版本)。它允许你传入一个自定义的协方差估计器对象(例如sklearn.covariance.ShrunkCovariance
)来替代标准的极大似然估计。 -
取值 : 一个实现了
fit
方法的协方差估计器对象。 -
依赖关系 : 仅当
solver='lsqr'
或'eigen'
时可用。 -
适用场景: 为高级用户提供极大的灵活性,可以尝试各种不同的协方差矩阵正则化方法。绝大多数用户不需要使用此参数。
我们来看一个示例:
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
from sklearn.preprocessing import StandardScaler
from sklearn.datasets import load_iris
# 加载数据
iris = load_iris()
X, y = iris.data, iris.target
# 1. 标准化数据(至关重要!)
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
# 2. 初始化LAD,保留2个维度
lda = LinearDiscriminantAnalysis(n_components=2)
# 3. 训练转换数据
X_lda = lad.fit_transform(X_scaled, y)
print("原始数据形状:", X.shape)
print("降维后数据:", X_lda)
运行结果:
