欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Fisher线性判别(LDA)python实现

程序员文章站 2022-07-14 21:15:29
...

LDA概述

首先,LDA是一个用于分类的有监督算法。
基本想法非常质朴,不失一般性的以二维平面二分类为例:
对于两类样本点,我们的目的是想找一条直线,将两类样本点映射到这条直线上时,使这两类之间的类间间距最大,类内间距最小。

图形上的直观理解如下。
对于第一张图,不同类映射到同一条直线上时出现混叠区域,难以判别类别。
对于第二张图,不同类映射到同一条直线上时没有混叠,分界鲜明(类间间距最大),且同一类内部样本距离样本中心点较近(类内间距最小)
Fisher线性判别(LDA)python实现

推导

不想看的可跳过,毕竟现在都是直接调包(不过建议看下,可以深入理解算法,并且再次体会数学的美妙)

整个算法的推导是一个数学上很优美的过程,详细过程如下。

注意:在模式识别中,所有向量都是m×1形式。

定义类均值向量:
Fisher线性判别(LDA)python实现

类内散度矩阵:
Fisher线性判别(LDA)python实现
物理意义上理解:就是各样本到自己所属类别中心点的欧式距离平方的和

类间散度矩阵:
Fisher线性判别(LDA)python实现
物理意义上理解:就是两类样本中心点的欧式距离的平方

假设我们已经找到最优的那条直线,将其记为向量u’
则新的(y1, y2)可以由下式得到:
Fisher线性判别(LDA)python实现
同理,计算出新的SwSb
Fisher线性判别(LDA)python实现

则按照LDA最初始的想法,我们想让投影得到的类间距离最大,类内距离最小,我们可以构造下面这个函数:
Fisher线性判别(LDA)python实现
即最大化该函数(在特征选择中也称该函数为JF判据,属于基于类内类间距离选择特征的一种判据)

接下来就是常规操作了,求导求极值
Fisher线性判别(LDA)python实现

注意其中最后一步中的 α 是代换掉了倒数第二个公式中的最后两项向量的内积(可轻易证明其内积为一常数)且 λ 也为常数(亦可证得)

因为向量的大小不影响方向,所以直线向量可摒弃前面的常系数

所以决策域可表示为
Fisher线性判别(LDA)python实现

算法总结

  1. 计算两类的均值向量
  2. 计算总类内散度阵
  3. 计算总类内散度阵的逆
  4. 按照 u 的计算公式求解 u
  5. 计算投影过后的两类的均值向量
  6. 计算分类阈值
  7. 对未知模式 x 判决模式类

可以看出,整个算法就是在进行数学运算,所以LDA是一个数学上非常优美的算法。

应用方向

  • 作为特征抽取的技术
  • 可以提高数据分析过程中的计算效率
  • 对于不适用与正则化的模型,可以降低因维度灾难带来的过拟合

算法实现(python)

因为其数学过于优美,理解其思路后计算机编程实现非常简单

函数实现:

import numpy as np


def LDA(x, y):      # x: all the input vector   y: labels


    x_1 = np.array([x[i] for i in range(len(x)) if y[i] == 1])
    x_2 = np.array([x[i] for i in range(len(x)) if y[i] == -1])

    mju1 = np.mean(x_1, axis=0)     # mean vector
    mju2 = np.mean(x_2, axis=0)

    sw1 = np.dot((x_1 - mju1).T, (x_1 - mju1))    # Within-class scatter matrix
    sw2 = np.dot((x_2 - mju2).T, (x_2 - mju2))
    sw = sw1 + sw2

    return np.dot(np.linalg.inv(sw), (mju1 - mju2))

测试:

import numpy as np
import matplotlib.pyplot as plt
import LDA


mean_1 = (-5, 0)   
mean_2 = (5, 0)
cov = [[1, 0],    
       [0, 1]]
size = 200          

np.random.seed(1)
x_1 = np.random.multivariate_normal(mean_1, cov, size)

np.random.seed(2)
x_2 = np.random.multivariate_normal(mean_2, cov, size)

x = np.vstack((x_1, x_2))
y = [-1] * 200 + [1] * 200      

plt.scatter(x_1[:, 0], x_1[:, 1], color='blue', marker='o', label='Positive')
plt.scatter(x_2[:, 0], x_2[:, 1], color='red', marker='x', label='Negative')
plt.legend(loc='upper left')
plt.title('Original Data')


w = LDA.LDA(x, y)

x1 = 1
y1 = -1 / w[1] * (w[0] * x1)

x2 = -1
y2 = -1 / w[1] * (w[0] * x2)

plt.plot([x1, x2], [y1, y2], 'r')
plt.show()

print(w)

网络原因结果图传不上去了,先这样吧,代码可以直接运行,我写的时候写成了两个文件,你们稍微改下调用时代码即可。