首先,LDA是一个用于分类的有监督算法。
基本想法非常质朴,不失一般性的以二维平面二分类为例:
对于两类样本点,我们的目的是想找一条直线,将两类样本点映射到这条直线上时,使这两类之间的类间间距最大,类内间距最小。
图形上的直观理解如下。
对于第一张图,不同类映射到同一条直线上时出现混叠区域,难以判别类别。
对于第二张图,不同类映射到同一条直线上时没有混叠,分界鲜明(类间间距最大),且同一类内部样本距离样本中心点较近(类内间距最小)
不想看的可跳过,毕竟现在都是直接调包(不过建议看下,可以深入理解算法,并且再次体会数学的美妙)
整个算法的推导是一个数学上很优美的过程,详细过程如下。
注意:在模式识别中,所有向量都是m×1形式。
类内散度矩阵:
物理意义上理解:就是各样本到自己所属类别中心点的欧式距离平方的和
类间散度矩阵:
物理意义上理解:就是两类样本中心点的欧式距离的平方
假设我们已经找到最优的那条直线,将其记为向量u’
则新的(y1, y2)可以由下式得到:
同理,计算出新的Sw和Sb
则按照LDA最初始的想法,我们想让投影得到的类间距离最大,类内距离最小,我们可以构造下面这个函数:
即最大化该函数(在特征选择中也称该函数为JF判据,属于基于类内类间距离选择特征的一种判据)
注意其中最后一步中的 α 是代换掉了倒数第二个公式中的最后两项向量的内积(可轻易证明其内积为一常数)且 λ 也为常数(亦可证得)
因为向量的大小不影响方向,所以直线向量可摒弃前面的常系数
可以看出,整个算法就是在进行数学运算,所以LDA是一个数学上非常优美的算法。
因为其数学过于优美,理解其思路后计算机编程实现非常简单
函数实现:
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)
网络原因结果图传不上去了,先这样吧,代码可以直接运行,我写的时候写成了两个文件,你们稍微改下调用时代码即可。