线性判别分析(Linear Discriminant Analysis)在图像识别领域应用广泛。这里LDA需要和自然语言处理中的隐含狄利克雷分布(Latent Dirichlet Allocation,简称LDA)区别开来。
官方介绍:将一个高维空间中的数据投影到一个较低维的空间中,且投影后要保证各个类别的类内方差小而类间均值差别大
和PCA的差距在于不要求投影后信息量最大,而是区分度最大,这也是主成分分析的不足之处。两种算法的选取需要看使用者的需求。
-
类间距离散度SB和类内距离散度SW
-
结论:
LDA算法计算步骤:
对d维数据进行标准化处理(d为特征数量)
对每一类别,计算d维的均值向量
构造类间的距离矩阵和类内的散度矩阵
计算矩阵的特征值和对应的特征向量
选取前k个特征值对应的特征向量,构造一个d x k维的转换矩阵W,特征向量以列的形式排列
使用转换矩阵W将样本映射到新的特征子空间上
代码一
import numpy as np
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
from sklearn.datasets import load_iris
import matplotlib.pyplot as plt
def lda(data, target, n_dim):
'''
:param data: (n_samples, n_features)
:param target: data class
:param n_dim: target dimension
:return: (n_samples, n_dims)
'''
clusters = np.unique(target)
if n_dim > len(clusters)-1:
print("K is too much")
print("please input again")
exit(0)
#within_class scatter matrix
Sw = np.zeros((data.shape[1],data.shape[1]))
for i in clusters:
datai = data[target == i]
datai = datai-datai.mean(0)
Swi = np.mat(datai).T*np.mat(datai)
Sw += Swi
#between_class scatter matrix
SB = np.zeros((data.shape[1],data.shape[1]))
u = data.mean(0) #所有样本的平均值
for i in clusters:
Ni = data[target == i].shape[0]
ui = data[target == i].mean(0) #某个类别的平均值
SBi = Ni*np.mat(ui - u).T*np.mat(ui - u)
SB += SBi
S = np.linalg.inv(Sw)*SB
eigVals,eigVects = np.linalg.eig(S) #求特征值,特征向量
eigValInd = np.argsort(eigVals)
eigValInd = eigValInd[:(-n_dim-1):-1]
w = eigVects[:,eigValInd]
data_ndim = np.dot(data, w)
return data_ndim
if __name__ == '__main__':
iris = load_iris()
X = iris.data
Y = iris.target
data_1 = lda(X, Y, 2)
data_2 = LinearDiscriminantAnalysis(n_components=2).fit_transform(X, Y)
plt.figure(figsize=(8,4))
plt.subplot(122)
plt.title("LDA")
plt.scatter(data_1[:, 0], data_1[:, 1], c = Y)
plt.subplot(121)
plt.title("natural data")
plt.scatter(data_2[:, 0], data_2[:, 1], c = Y)
plt.savefig("LDA.png",dpi=600)
plt.show()
代码二
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import sklearn.datasets
# 生成3类3维特征的数据集
X, y = sklearn.datasets.make_classification(n_samples=1000, n_features=3, n_redundant=0, n_classes=3, n_informative=2,
n_clusters_per_class=1, class_sep=0.5, random_state=10)
fig = plt.figure()
ax = Axes3D(fig, rect=[0, 0, 1, 1], elev=30, azim=20)
ax.scatter(X[:, 0], X[:, 1], X[:, 2], marker='o', c=y)
plt.show()
# 第一步,标准化数据集
Xmean = X.mean(axis=0)
Xstd = X- Xmean
# 第二步,计算每个类别的向量均值
mean_vec = []
for k in np.unique(y):
mean_vec.append(np.mean(Xstd[y == k],axis=0)) #每一个特征维度的均值,这里规模是3*1
# 第三步,计算类内散度矩阵和类间散度矩阵
d = 3
Sw = np.zeros((d, d)) # 类内散度矩阵,规模是d*d(特征维度)
for k in np.unique(y):
# numpy对于一维向量,矩阵相乘需要用reshape得到d*d维矩阵,否则是一个数字
s = (Xstd[y == k].T).dot(Xstd[y == k]) / (y[y == k].shape[0]) - (mean_vec[k].reshape(d, 1)).dot(
mean_vec[k].reshape(d, 1).T)
Sw = Sw + s
Sb = np.zeros((d, d)) # 类间散度矩阵,规模是d*d(特征维度)
for k in range(len(mean_vec)):
for j in range(k + 1, len(mean_vec)):
sm = np.array(mean_vec[k] - mean_vec[j]).reshape(d, 1)
Sb = Sb + np.dot(sm, sm.T)
# 第四步,构造S矩阵(Sw逆矩阵乘以Sb矩阵),并求解特征向量和特征根
S = np.dot(np.linalg.inv(Sw),Sb)
e,v = np.linalg.eig(S) #一列为一个特征向量
# 第五步,组合W矩阵并计算降维后数据集Z
W = np.column_stack((v[:,0],v[:,1])) #向量组合用np.column_stack
Z = -np.dot(Xstd,W) #得到降维后的数据集
# 最后,来看看降维效果
plt.scatter(Z[:, 0], Z[:, 1],marker='o',c=y)
plt.show()
# 直接调用sklearn包看看,结果和手动实现是否一致。
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
lda = LinearDiscriminantAnalysis(n_components=2)
lda.fit(Xstd,y)
X_new = lda.transform(Xstd)
plt.scatter(X_new[:, 0], X_new[:, 1],marker='o',c=y)
plt.show()