线性判别分析LDA:详解及数学原理

    科技2025-05-27  7

    目录

    简介数学分析Python实现简单的LDA


    简介

            线性判别分析 (Linear Discriminant Analysis,简称 LDA)是一种经典的线性学习方法。并且LDA是一种监督学习降维技术

    思想:         给定训练样例集,设法将样例投影到一条直线上,使得同类样例的投影点尽可能接近、 异类样例 的投影点尽可能远离(有些像中心损失的思想)。         在对新样本进行分类时,将其投影到 同样的这条直线上,再根据投影点的位置来确定新样本的类别。

    数学分析

            给定数据集 D ∈ { ( X i , Y i ) } i − 1 m D\in \lbrace(Xi , Yi)\rbrace^m_{i-1} D{(XiYi)}i1m,旦 Y i ∈ { 0 , 1 } Y_i \in\lbrace {0, 1 }\rbrace Yi{01} , 令 X i , μ i , Σ i X_i,\mu_i,\Sigma_i Xi,μi,Σi 分别表示第 i ∈ { 0 , 1 } i\in \lbrace{0 , 1}\rbrace i{01} 类样例的集合、均值向量、协方差矩阵。

    这里小小的回忆一下协方差与协方差矩阵: 协方差矩阵是一个矩阵,其每个元素是各个向量元素之间的协方差。而协方差描述了向量之间的相关程度(关于协方差,可以看这篇博客写的很好:终于明白协方差的意义了)

            若将数据投影到直线 w w w上 ,则两类样本的中心在直线上的投影分别为 w T μ 0 w_Tμ_0 wTμ0 w T μ 1 w_Tμ_1 wTμ1

            若将所有样本点都投影到直线上,则两类样本的协方差分别为 w T Σ 0 w w_T\Sigma_0w wTΣ0w w T Σ 1 w w_T\Sigma_1w wTΣ1w

            欲使同类样例的投影点尽可能接近,可以让同类样例投影点的协方差尽可能小:即 w T Σ 0 w + w T Σ 1 w w_T\Sigma_0w+w_T\Sigma_1w wTΣ0w+wTΣ1w 尽可能小

            使异类样例的投影点尽可能远离,类中心之间的距离尽可能大,即: ∣ ∣ w T μ 0 − w T μ 1 ∣ ∣ 2 2 ||w_Tμ_0-w_Tμ_1||^2_2 wTμ0wTμ122 尽可能大( ∣ ∣ ⋅ ∣ ∣ 2 2 ||\centerdot ||^2_2 22 为L2范数的平方)

            同时考虑二者,即最大化下式: 类内散度矩阵:

    类问散度矩阵:

    J J J函数可重写为:

    也被称为 S b S_b Sb S w S_w Sw 的"广义瑞利商"

    那么 w w w如何求呢?

            对于广义瑞利商,分子分母上的 w T ∗ ∗ w w^T**w wTw,只与其方向有关,我们可以将 w T S w w w^TS_ww wTSww看作1,因此最大化原函数 J J J变为最小化: 由拉格朗日乘子法,上式等价于: S b w S_bw Sbw 的方向恒为 μ 0 − μ 1 μ_0- μ_1 μ0μ1,令: 故 w w w

    Python实现简单的LDA

    import numpy as np import matplotlib.pyplot as plt from sklearn.datasets import make_classification def func(x, w): return np.dot((x), w) def LDA(X, y): # 根据标签分为两个数据集 X1 = np.array([X[i] for i in range(len(X)) if y[i] == 0]) X2 = np.array([X[i] for i in range(len(X)) if y[i] == 1]) len1 = len(X1) len2 = len(X2) # 求中心点 X1_Center = np.mean(X1, axis=0) print(X1_Center) X2_Center = np.mean(X2, axis=0) print(X2_Center) # 求协方差 cov1 = np.dot((X1 - X1_Center ).T, (X1 - X1_Center )) cov2 = np.dot((X2 - X2_Center).T, (X2 - X2_Center)) # 求类内散度 Sw = cov1 + cov2 # 求w # np.mat()将输入解释为一个矩阵 # np.mat().I求逆 w = np.dot(np.mat(Sw).I, (X1_Center - X2_Center).reshape((len(X1_Center), 1))) # 输出 X1_new = func(X1, w) X2_new = func(X2, w) y1_new = [1 for i in range(len1)] y2_new = [2 for i in range(len2)] return X1_new, X2_new, y1_new, y2_new if '__main__' == __name__: X, y = make_classification(n_samples=500, n_features=2, n_redundant=0, n_classes=2, n_informative=1, n_clusters_per_class=1, class_sep=0.5, random_state=10) X1_new, X2_new, y1_new, y2_new = LDA(X, y) plt.scatter(X[:, 0], X[:, 1], marker='o', c=y) plt.show() plt.plot(X1_new, y1_new, 'b*') plt.plot(X2_new, y2_new, 'ro') plt.show()

    下面是均值向量输出:

    [-4.91767118e-01 -4.15692170e-04] [ 0.50795852 -0.12563275]

    原始数据分布: 经过LDA后的数据分布:

    Processed: 0.013, SQL: 8