Fisher线性判别(LDA)python实现

LDA概述

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

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

推导

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

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

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

定义类均值向量:
Fisher线性判别(LDA)python实现_第2张图片

类内散度矩阵:
在这里插入图片描述
物理意义上理解:就是各样本到自己所属类别中心点的欧式距离平方的和

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

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

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

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

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

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

所以决策域可表示为
Fisher线性判别(LDA)python实现_第8张图片

算法总结

  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)

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

你可能感兴趣的:(Pattern,Recognition)