《机器学习公式推导与代码实现》chapter5-线性判别分析LDA

《机器学习公式推导与代码实现》学习笔记,记录一下自己的学习过程,详细的内容请大家购买作者的书籍查阅。

线性判别分析

线性判别分析(linear discriminant analysis, LDA)是一种经典的线性分类方法,其基本思想是将数据投影到低维空间,使得同类数据尽可能接近,异类数据尽可能疏远。

另外线性判别分析能够通过投影来降低样本维度,并且在投影过程中用到了标签信息,线性判别分析是一种监督降维方法
在这里插入图片描述

1 LDA数学推导

在这里插入图片描述
在这里插入图片描述

2 基于numpy的LDA算法实现

完整的LDA算法流程如下:

  • (1)对训练集按类别进行分组;
  • (2)分别计算每组样本的均值和协方差;
  • (3)计算类间散度矩阵 S w S_{w} Sw;
  • (4)计算两类样本的均值差 μ 0 − μ 1 \mu _{0} -\mu_{1} μ0μ1;
  • (5)对类间散度矩阵 S w S_{w} Sw进行奇异值分解,并求逆;
  • (6)根据$S_{w}^{-1} \left ( \mu _{0} -\mu _{1} \right ) 得到 得到 得到w$;
  • (7)计算投影后的数据点 Y = w X Y = wX Y=wX

模型定义:

import numpy as np

class LDA():
    def __init__(self): # 初始化权重矩阵
        self.w = None
    
    def calc_cov(self, X, Y=None): # 计算协方差矩阵
        m = X.shape[0]
        # 将数据缩放到均值为0,标准差为1的标准正态分布
        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 fit(self, X, y): # LDA拟合过程
        
        # 按类分组
        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) # 如果 u0 - u1 是一个标量,则将其转换为长度为1的一维数组。如果 u0 - u1 是一个数组,则保持不变

        # 利用 SVD 分解,我们可以通过计算矩阵 U、Σ 和 V 来得到原始矩阵的逆矩阵的近似
        U, S, V = np.linalg.svd(Sw) # # 对类内散度矩阵进行奇异值分解
        Sw_ = np.dot(np.dot(V.T, np.linalg.pinv(np.diag(S))), U.T) # 计算类内散度矩阵的逆
        
        self.w = Sw_.dot(mean_diff) # 计算w
    
    def predict(self, X): # LDA分类预测
        y_pred = []
        for sample in X:
            h = sample.dot(self.w)
            y = 1 * (h < 0) # 如果h小于0,则将y设置为1,否则将y设置为0
            y_pred.append(y)
        return y_pred

读取数据:

from sklearn import datasets
from sklearn.model_selection import train_test_split

data = datasets.load_iris()
X = data.data
y = data.target
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)
X_train.shape, X_test.shape, y_train.shape, y_test.shape
((80, 4), (20, 4), (80,), (20,))

数据测试:

lda = LDA()
lda.fit(X_train, y_train)
y_pred = lda.predict(X_test)

from sklearn.metrics import accuracy_score
accuracy = accuracy_score(y_test, y_pred)
print(accuracy)
0.85

结果可视化:

import matplotlib.pyplot as plt

class Plot():
    def __init__(self): 
        self.cmap = plt.get_cmap('viridis')

    def _transform(self, X, dim):
        covariance = LDA().calc_cov(X)
        eigenvalues, eigenvectors = np.linalg.eig(covariance)
        # Sort eigenvalues and eigenvector by largest eigenvalues
        idx = eigenvalues.argsort()[::-1]
        eigenvalues = eigenvalues[idx][:dim]
        eigenvectors = np.atleast_1d(eigenvectors[:, idx])[:, :dim]
        # Project the data onto principal components
        X_transformed = X.dot(eigenvectors)

        return X_transformed

    # Plot the dataset X and the corresponding labels y in 2D using PCA.
    def plot_in_2d(self, X, y=None, title=None, accuracy=None, legend_labels=None):
        X_transformed = self._transform(X, dim=2)
        x1 = X_transformed[:, 0]
        x2 = X_transformed[:, 1]
        class_distr = []

        y = np.array(y).astype(int)

        colors = [self.cmap(i) for i in np.linspace(0, 1, len(np.unique(y)))]

        # Plot the different class distributions
        for i, l in enumerate(np.unique(y)):
            _x1 = x1[y == l]
            _x2 = x2[y == l]
            _y = y[y == l]
            class_distr.append(plt.scatter(_x1, _x2, color=colors[i]))

        # Plot legend
        if not legend_labels is None: 
            plt.legend(class_distr, legend_labels, loc=1)

        # Plot title
        if title:
            if accuracy:
                perc = 100 * accuracy
                plt.suptitle(title)
                plt.title("Accuracy: %.1f%%" % perc, fontsize=10)
            else:
                plt.title(title)

        # Axis labels
        plt.xlabel('class 1')
        plt.ylabel('class 2')

        plt.show()

Plot().plot_in_2d(X_test, y_pred, title="LDA", accuracy=accuracy)
Plot().plot_in_2d(X_test, y_test, title="LDA", accuracy=accuracy)

在这里插入图片描述

3 基于sklearn的LDA算法实现

from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
clf = LinearDiscriminantAnalysis()
clf.fit(X_train, y_train)
y_pred = clf.predict(X_test)
accuracy = accuracy_score(y_test, y_pred)
print(accuracy)
1.0

笔记本_Github地址

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jiawen9

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值