机器学习——线性判别分析原理及python代码实现

《机器学习:公式推导与代码实践》鲁伟著读书笔记。
线性判别分析(Linear Discriminant Analysis,LDA)是一种经典的线性分类方法,其基本思想是将数据投影到低维空间,使得同类数据尽可能接近,异类数据尽可能疏远,所以线性判别分析也是一种监督降维算法。

LDA公式推导

线性判别分析的基本思想是将数据集投影到一条直线上,使得同类样本的投影点尽可能接近,不同类样本的投影点尽可能疏远。按此原理训练完成之后,将新样本投影到该直线上,根据投影点的位置来确定新样本点的类别。以二维变量为例,“+”表示正例,“-”表示反例。LDA的优化目标就是使投影后的类内距离小,类间距离大。
机器学习——线性判别分析原理及python代码实现_第1张图片
LDA二维图片来源
下面对二分类LDA的基本原理和数学推导,给定数据集 D = { ( x 1 , y 1 ) , ( x 2 , y 2 ) , . . . , ( x m , y m ) } D={\left \{(x_{1},y_{1}),(x_{2},y_{2}),...,(x_{m},y_{m})\right \}} D={(x1,y1),(x2,y2),...,(xm,ym)}其中, x i x_{i} xi为样本的n维特征向量, y ∈ ( 0 , 1 ) y\in (0,1) y(0,1)为样本的类别。令 N j N_{j} Nj(j为类别,0或1)为第j类样本的数量, X j X_{j} Xj为第j类样本的集合, μ j \mu_{j} μj为第j类样本的均值向量, Σ j \Sigma_{j} Σj为第j类样本的协方差矩阵。其计算公式为:
μ j \mu_{j} μj的表达式为: μ j = 1 N j Σ x ∈ X j x \mu_{j}=\frac{1}{N_{j}}\Sigma_{x\in X_{j}}x μj=Nj1ΣxXjx Σ j \Sigma_{j} Σj的表达式为: Σ j = Σ x ∈ X j ( x − μ j ) ( x − μ j ) T \Sigma_{j}=\Sigma_{x\in X_{j}}(x-\mu_{j})(x-\mu_{j})^{T} Σj=ΣxXj(xμj)(xμj)T由于是二分类模型,因此我们只需要将数据投影到一条直线上,假设投影直线为向量 ω \omega ω,对于任意一个样本 x x x,他在直线上的投影为 ω T x \omega^{T}x ωTx。则投影之后,每类样本的均值向量和协方差的计算如下:
投影之后每类样本的均值向量: 1 N j Σ x ∈ X j ω T x = ω T 1 N j Σ x ∈ X j x = ω T μ j \frac{1}{N_{j}}\Sigma_{x\in X_{j}}\omega^{T}x=\omega^{T}\frac{1}{N_{j}}\Sigma_{x\in X_{j}}x=\omega^{T}\mu_{j} Nj1ΣxXjωTx=ωTNj1ΣxXjx=ωTμj投影之后每类样本的协方差矩阵: Σ x ∈ X j ( ω T x − ω T μ j ) ( ω T x − ω T μ j ) T = ω T Σ x ∈ X j ( x − μ j ) ( x − μ j ) T ω = ω T Σ j ω \Sigma_{x\in X_{j}}(\omega^{T}x-\omega^{T}\mu_{j})(\omega^{T}x-\omega^{T}\mu_{j})^{T}=\omega^{T}\Sigma_{x\in X_{j}}(x-\mu_{j})(x-\mu_{j})^{T}\omega=\omega^{T}\Sigma_{j} \omega ΣxXj(ωTxωTμj)(ωTxωTμj)T=ωTΣxXj(xμj)(xμj)Tω=ωTΣjωLDA模型的优化目标是使同类样本的投影点尽可能接近,我们可以使同类样本的投影点的协方差尽可能小,即 ω T Σ 0 ω + ω T Σ 1 ω \omega^{T}\Sigma_{0} \omega+\omega^{T}\Sigma_{1} \omega ωTΣ0ω+ωTΣ1ω;异类样本的投影点尽可能疏远,可以使类中心点之间的距离尽可能远,即 ∣ ∣ ω T μ 0 − ω T μ 1 ∣ ∣ 2 2 ||\omega^{T}\mu_{0}-\omega^{T}\mu_{1}||^{2}_{2} ωTμ0ωTμ122尽可能大。综合考虑两个优化目标的情况下,目标函数可以定义为: arg max  J ( ω ) = ∣ ∣ ω T μ 0 − ω T μ 1 ∣ ∣ 2 2 ω T Σ 0 ω + ω T Σ 1 ω = ω T ( μ 0 − μ 1 ) ( μ 0 − μ 1 ) T ω ω T ( Σ 0 + Σ 1 ) ω \text {arg max }J(\omega)=\frac{||\omega^{T}\mu_{0}-\omega^{T}\mu_{1}||^{2}_{2}}{\omega^{T}\Sigma_{0} \omega+\omega^{T}\Sigma_{1} \omega}=\frac{\omega^{T}(\mu_{0}-\mu_{1})(\mu_{0}-\mu_{1})^{T}\omega}{\omega^{T}(\Sigma_{0}+\Sigma_{1} )\omega} arg max J(ω)=ωTΣ0ω+ωTΣ1ωωTμ0ωTμ122=ωT(Σ0+Σ1)ωωT(μ0μ1)(μ0μ1)Tω定义类内散度矩阵为 S ω = Σ 0 + Σ 1 S_{\omega}=\Sigma_{0}+\Sigma_{1} Sω=Σ0+Σ1,类间散度矩阵为 S b = ( μ 0 − μ 1 ) ( μ 0 − μ 1 ) T S_{b}=(\mu_{0}-\mu_{1})(\mu_{0}-\mu_{1})^{T} Sb=(μ0μ1)(μ0μ1)T。则目标函数可以改写为: arg max  J ( ω ) = ω T S b ω ω T S ω ω \text {arg max }J(\omega)=\frac{\omega^{T}S_{b}\omega}{\omega^{T}S_{\omega}\omega} arg max J(ω)=ωTSωωωTSbω为了对目标函数进行简化,我们令 ω T S ω ω = 1 \omega^{T}S_{\omega}\omega=1 ωTSωω=1,则可以将其视作目标函数的约束条件。具体如下: arg max  F ( ω ) = ω T S b ω \text {arg max }F(\omega)=\omega^{T}S_{b}\omega arg max F(ω)=ωTSbω s.t.  ω T S ω ω = 1 \text {s.t. }\omega^{T}S_{\omega}\omega=1 s.t. ωTSωω=1

拉格朗日函数问题

定义(拉格朗日函数):对于优化问题:
min  f ( u ) \text{min }f(u) min f(u) s.t.  g i ( u ) ≤ 0 , i = 1 , 2 , 3 , . . . , m h i ( u ) = 0 , j = 1 , 2 , 3 , . . . , n \text{s.t. }g_{i}(u) \leq 0,i=1,2,3,...,m \\ h_{i}(u)=0,j=1,2,3,...,n s.t. gi(u)0,i=1,2,3,...,mhi(u)=0,j=1,2,3,...,n定义其拉格朗日函数便为: L ( u , α , β ) : = f ( u ) + ∑ i = 1 m α i g i ( u ) + ∑ j = 1 n β j h j ( u ) \mathcal{L}(\boldsymbol{u}, \boldsymbol{\alpha}, \boldsymbol{\beta}):=f(\boldsymbol{u})+\sum_{i=1}^{m} \alpha_{i} g_{i}(\boldsymbol{u})+\sum_{j=1}^{n} \beta_{j} h_{j}(\boldsymbol{u}) L(u,α,β):=f(u)+i=1mαigi(u)+j=1nβjhj(u)其中, α i > 0 \alpha_{i}>0 αi>0

利用拉格朗日函数优化目标函数

利用拉格朗日函数可得: L ( ω ) = ω T S b ω − λ ( ω T S ω ω − 1 ) \mathcal{L}(\omega)=\omega^{T}S_{b}\omega-\lambda(\omega^{T}S_{\omega}\omega-1) L(ω)=ωTSbωλ(ωTSωω1)取上式对 ω \omega ω求导可得: d L ( ω ) d ω = 2 S b ω − 2 λ S ω ω = 0 \frac{d\mathcal{L}(\omega)}{d\omega}=2S_{b}\omega-2\lambda S_{\omega}\omega=0 dωdL(ω)=2Sbω2λSωω=0即: 2 S b ω = 2 λ S ω ω 2S_{b}\omega=2\lambda S_{\omega}\omega 2Sbω=2λSωω S b ω = λ S ω ω S_{b}\omega=\lambda S_{\omega}\omega Sbω=λSωω如果 S ω S_{\omega} Sω可逆,则: λ ω = S ω − 1 S b ω \lambda \omega=S_{\omega}^{-1}S_{b}\omega λω=Sω1Sbω λ \lambda λ仅仅是一个参数,所以上式等于: ω = λ S ω − 1 S b ω \omega=\lambda S_{\omega}^{-1}S_{b}\omega ω=λSω1Sbω考虑到 S ω S_{\omega} Sω矩阵数值解的稳定性,如果矩阵不可逆,则我们可以对矩阵 S ω S_{\omega} Sω进行奇异值分解,然后再对分解后的矩阵进行求逆操作,即可得到 S ω − 1 S_{\omega}^{-1} Sω1 S ω = U Σ V − 1 S_{\omega}=U\Sigma V^{-1} Sω=UΣV1由于对于二分类模型, S b ω = ( μ 0 − μ 1 ) ( μ 0 − μ 1 ) T ω S_{b}\omega=(\mu_{0}-\mu_{1})(\mu_{0}-\mu_{1})^{T}\omega Sbω=(μ0μ1)(μ0μ1)Tω,可以看出 S b ω S_{b}\omega Sbω ( μ 0 − μ 1 ) (\mu_{0}-\mu_{1}) (μ0μ1)是平行的,所以: S b ω = k ( μ 0 − μ 1 ) S_{b}\omega=k(\mu_{0}-\mu_{1}) Sbω=k(μ0μ1)所以, ω \omega ω可以表示为: ω = λ S ω − 1 k ( μ 0 − μ 1 ) \omega=\lambda S_{\omega}^{-1}k(\mu_{0}-\mu_{1}) ω=λSω1k(μ0μ1)去除参数可得: ω = S ω − 1 ( μ 0 − μ 1 ) \omega=S_{\omega}^{-1}(\mu_{0}-\mu_{1}) ω=Sω1(μ0μ1)我们只需要求出原始数据集二分类样本的均值和方差就可以确定最佳的投影方向。

LDA算法的具体流程

  1. 对训练数据集根据组别进行分组;
  2. 分别计算每组样本的均值和协方差;
  3. 计算类内散度矩阵 S ω = Σ 0 + Σ 1 S_{\omega}=\Sigma_{0}+\Sigma_{1} Sω=Σ0+Σ1
  4. 计算两类样本的均值差 ( μ 0 − μ 1 ) (\mu_{0}-\mu_{1}) (μ0μ1);
  5. S ω S_{\omega} Sω的逆矩阵 S ω − 1 S_{\omega}^{-1} Sω1,若矩阵不可逆,则可用奇异值分解的方式求解;
  6. 根据 S ω − 1 ( μ 0 − μ 1 ) S_{\omega}^{-1}(\mu_{0}-\mu_{1}) Sω1(μ0μ1)得到 ω \omega ω;
  7. 最后计算投影后的数据点 Y = ω X Y=\omega X Y=ωX

对数几率回归的NumPy手撕代码

Numpy LDA实现

import numpy as np

class LDA():
    def __init__(self):
        # 初始化权重矩阵
        self.w = None
        
    # 计算协方差矩阵
    def calc_cov(self, X, Y=None):
        m = X.shape[0]
        # 数据标准化
        X = (X - np.mean(X, axis=0))/np.std(X, axis=0)
        Y = X if Y == None else (Y - np.mean(Y, axis=0))/np.std(Y, axis=0)
        return 1 / m * np.matmul(X.T, Y)
    
    # 对数据进行投影
    def project(self, X, y):
        self.fit(X, y)
        X_projection = X.dot(self.w)
        return X_projection
    
    # LDA拟合过程
    def fit(self, X, y):
        # 按类分组
        X0 = X[y == 0]
        X1 = X[y == 1]

        # 分别计算两类数据自变量的协方差矩阵
        sigma0 = self.calc_cov(X0)
        sigma1 = self.calc_cov(X1)
        # 计算类内散度矩阵
        Sw = sigma0 + sigma1

        # 分别计算两类数据自变量的均值和差
        u0, u1 = np.mean(X0, axis=0), np.mean(X1, axis=0)
        mean_diff = np.atleast_1d(u0 - u1)

        # 对类内散度矩阵进行奇异值分解
        U, S, V = np.linalg.svd(Sw)
        # 计算类内散度矩阵的逆
        Sw_ = np.dot(np.dot(V.T, np.linalg.pinv(np.diag(S))), U.T)
        # 计算w
        self.w = Sw_.dot(mean_diff)

    
    # LDA分类预测
    def predict(self, X):
        y_pred = []
        for sample in X:
            h = sample.dot(self.w)
            y = 1 * (h < 0)
            y_pred.append(y)
        return y_pred

LDA算法的数据测试:

from sklearn import datasets
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score

#导入数据集
data = datasets.load_iris()
#数据与标签
X = data.data
y = data.target
#仅取标签为0,1的数据
X = X[y != 2]
y = y[y != 2]
#划分数据集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=41)
#创建模型
lda = LDA()
#LDA模型拟合
lda.fit(X_train, y_train)
#预测
y_pred = lda.predict(X_test)
#计算准确度
accuracy = accuracy_score(y_test, y_pred)
print(accuracy)

accuracy:0.85

你可能感兴趣的:(机器学习,python,python,列表,算法)