LDA线性判别分析的思想十分简单,将给定的训练样例集投影到一条直线上,我们希望投影过后,不同类的数据点尽量远离,同类数据点尽量聚合。设Xi表示i类数据的集合i∈(0,1),μi为i类数据集合的均值向量
类内散度的定义:
使用方差来度量类内的离散程度,因为都是向量表示形式,所以平方和用向量乘向量的转置表示
类间散度矩阵:
使用均值的方差表示两种数据类之间的离散程度
我们要使类间散度越大越好,类内散度越小越好。
所以我们的最小化目标是:
我们只要求出投影后,对应数据点的位置,就可以得到我们想要的模型。
设投影直线为:
我们以二维图像为例:
(x',y')为(x,y)在直线上的投影,要直接求出(x',y')是比较复杂的,可以求但没必要
上式的意义都是两点之间的距离的平方,所以我们直接求距离就可以了
因为投影后,所有的点在一条直线上,所以,点与点之间的距离,等于两点到原点的距离之差,而投影点到原点的距离就很好求了。
我们用向量乘积的形式表示一下:
(x,y)到原点的距离:|(x,y)|
(x',y')到原点的距离:cosθ|(x,y)|
cosθ可以表示为:
所以:
看上去,好像没有解决问题,但是我们有一下考虑:
向量除以向量的模,等于单位向量,我们不能直接求得单位向量,但是我们已知直线的方向向量 (投影直线的方向,它的参数):
则我们加入一个未知量(0<λ<1 )来表示单位向量:
所以:
我们将(x,y)这样的点表示的向量直接表示为一个参数向量,就和 我们的样例中的一个X=(x0,x1,....,xn)这样,所以一个向量表示的样例参数经过投影后到原点的距离为:
所以,投影后的类内散度矩阵应该表示为:
用Sw表示投影前的类内散度矩阵,所以投影后的类内散度矩阵为:
类间散度矩阵表示为:
用Sb表示投影前的类间散度矩阵,所以投影后的类间散度矩阵为:
所以我们的优化函数为:
我们的最优化函数得出来了,我们只要解出来就可以了(解出最优化参数ω)。
此时我们就可以使用拉格朗日乘子法来求解了
观察发现分数上下都有
所以结果与ω 向量的模(大小)无关,只与它的方向有关,那么分子分母可以取任意值,会产生无穷多解,所以我们将分母限制为1,并作为拉格朗日的约束条件
所以我们令:
优化函数等价为:
由 拉格朗日乘数法有:
拉格朗日函数为:
对ω求导等于0:
根据Sb的定义式,可以看出他的方向恒为(μ0-μ1) ,所以我们令:
因为Sw为向量,所以两边同乘,Sw的逆,所以:
因为有些矩阵是没有逆矩阵的,所以我们使用广义逆矩阵,来确保有解。
推导过程一大串,但是实现却很简单:
我们自己生成一个数据集:
def createDataSet():
#类别1
X1 = np.mat(np.random.random((8, 2)) * 5 + 15)
#类别2
X2 = np.mat(np.random.random((8, 2)) * 5 + 2)
return X1, X2
求各个属性的均值:
def average(dataset):
ave = []
a, b = np.shape(dataset)
for i in range(b):
n = np.sum(dataset[:,i]) / a
ave.append(n)
return np.array(ave)
求单一类的类内散度矩阵:
def compute_sw(dataset, ave):
sw = 0
a, b = np.shape(dataset)
for i in range(a - 1):
sw += np.dot(dataset[i,:] - ave, (dataset[i,:] - ave).T)
return np.array(sw)
因为有些矩阵是没有逆矩阵的,为了使任意数据集都有结果,我们使用广义逆矩阵:
x1_sw = compute_sw(x1_x, x1_x_ave)
x2_sw = compute_sw(x2_x, x2_x_ave)
Sw = x1_sw + x2_sw
#求广义逆
pinv = np.linalg.pinv(Sw)
w = np.multiply(x1_x_ave - x2_x_ave, pinv)[0,:]
我们就得到了,最优投影直线的参数w ,从而得到最优投影直线