简介
线性判别分析 (Linear Discriminant Analysis,简称 LDA)是一种经典的线性学习方法。并且LDA是一种监督学习的降维技术。
思想:
给定训练样例集,设法将样例投影到一条直线上,使得同类样例的投影点尽可能接近、 异类样例 的投影点尽可能远离(有些像中心损失的思想)。
在对新样本进行分类时,将其投影到 同样的这条直线上,再根据投影点的位置来确定新样本的类别。
数学分析
给定数据集 D ∈ { ( X i , Y i ) } i − 1 m D\in \lbrace(Xi , Yi)\rbrace^m_{i-1} D∈{(Xi,Yi)}i−1m,旦 Y i ∈ { 0 , 1 } Y_i \in\lbrace {0, 1 }\rbrace Yi∈{0,1} , 令 X i , μ i , Σ i X_i,\mu_i,\Sigma_i Xi,μi,Σi 分别表示第 i ∈ { 0 , 1 } i\in \lbrace{0 , 1}\rbrace i∈{0,1} 类样例的集合、均值向量、协方差矩阵。
这里小小的回忆一下协方差与协方差矩阵: 协方差矩阵是一个矩阵,其每个元素是各个向量元素之间的协方差。而协方差描述了向量之间的相关程度(关于协方差,可以看这篇博客写的很好:终于明白协方差的意义了)
若将数据投影到直线 w w w上 ,则两类样本的中心在直线上的投影分别为 w T μ 0 w_Tμ_0 wTμ0 和 w T μ 1 w_Tμ_1 wTμ1
若将所有样本点都投影到直线上,则两类样本的协方差分别为 w T Σ 0 w w_T\Sigma_0w wTΣ0w和 w T Σ 1 w w_T\Sigma_1w wTΣ1w
欲使同类样例的投影点尽可能接近,可以让同类样例投影点的协方差尽可能小:即 w T Σ 0 w + w T Σ 1 w w_T\Sigma_0w+w_T\Sigma_1w wTΣ0w+wTΣ1w 尽可能小
使异类样例的投影点尽可能远离,类中心之间的距离尽可能大,即: ∣ ∣ w T μ 0 − w T μ 1 ∣ ∣ 2 2 ||w_Tμ_0-w_Tμ_1||^2_2 ∣∣wTμ0−wTμ1∣∣22 尽可能大( ∣ ∣ ⋅ ∣ ∣ 2 2 ||\centerdot ||^2_2 ∣∣⋅∣∣22 为L2范数的平方)
同时考虑二者,即最大化下式:
类内散度矩阵:
类问散度矩阵:
故
J
J
J函数可重写为:
也被称为
S
b
S_b
Sb 与
S
w
S_w
Sw 的"广义瑞利商"
那么 w w w如何求呢?
对于广义瑞利商,分子分母上的
w
T
∗
∗
w
w^T**w
wT∗∗w,只与其方向有关,我们可以将
w
T
S
w
w
w^TS_ww
wTSww看作1,因此最大化原函数
J
J
J变为最小化:
由拉格朗日乘子法,上式等价于:
S
b
w
S_bw
Sbw 的方向恒为
μ
0
−
μ
1
μ_0- μ_1
μ0−μ1,令:
故
w
w
w:
Python实现简单的LDA
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_classification
def func(x, w):
return np.dot((x), w)
def LDA(X, y):
# 根据标签分为两个数据集
X1 = np.array([X[i] for i in range(len(X)) if y[i] == 0])
X2 = np.array([X[i] for i in range(len(X)) if y[i] == 1])
len1 = len(X1)
len2 = len(X2)
# 求中心点
X1_Center = np.mean(X1, axis=0)
print(X1_Center)
X2_Center = np.mean(X2, axis=0)
print(X2_Center)
# 求协方差
cov1 = np.dot((X1 - X1_Center ).T, (X1 - X1_Center ))
cov2 = np.dot((X2 - X2_Center).T, (X2 - X2_Center))
# 求类内散度
Sw = cov1 + cov2
# 求w
# np.mat()将输入解释为一个矩阵
# np.mat().I求逆
w = np.dot(np.mat(Sw).I, (X1_Center - X2_Center).reshape((len(X1_Center), 1)))
# 输出
X1_new = func(X1, w)
X2_new = func(X2, w)
y1_new = [1 for i in range(len1)]
y2_new = [2 for i in range(len2)]
return X1_new, X2_new, y1_new, y2_new
if '__main__' == __name__:
X, y = make_classification(n_samples=500, n_features=2, n_redundant=0, n_classes=2,
n_informative=1, n_clusters_per_class=1, class_sep=0.5, random_state=10)
X1_new, X2_new, y1_new, y2_new = LDA(X, y)
plt.scatter(X[:, 0], X[:, 1], marker='o', c=y)
plt.show()
plt.plot(X1_new, y1_new, 'b*')
plt.plot(X2_new, y2_new, 'ro')
plt.show()
下面是均值向量输出:
[-4.91767118e-01 -4.15692170e-04]
[ 0.50795852 -0.12563275]
原始数据分布:
经过LDA后的数据分布: