线性判别分析(LDA,linear discriminant analysis)
线性判别分析是特征变换算法,也是有监督分类器。
LDA的目标是提取一个新的坐标系,将原始数据集投影到一个低维空间中。
在低维空间中获得最佳的类别可分性。
PCA是使样本的方差最大化,方差最大化可以使分类变得更简单,但不是最直接的。而LDA更加的直接,LDA是将样本空间投影到低维的线性可分割空间
比如将二维投射到一维
图中的斜线
按照这条投影的时候样本并不能完全分开,中间会有重叠的部分,换一条线
可以看出这个的效果明显比上一个要好,LDA的要找的就是这条直线。
LDA的工作流程
1.计算每个类别的均值向量;
2.计算类内和类间的散布矩阵;
3.计算散布矩阵的特征值和特征向量;
4.降序排列特征值,保留前个特征向量;
5.使用前几个特征向量将数据投影到新空间。
第一步计算的是X的,第二步要用到标签。
现在用代码实现这五个步骤
from sklearn.datasets import load_iris import numpy as np iris = load_iris() iris_X, iris_y = iris.data, iris.target # 创建X和y变量,存储特征和响应列 label_dict = {i: k for i, k in enumerate(iris.target_names)} mean_vectors = [] # 存储每个类别的均值向量 for cl in [0, 1, 2]: class_mean_vector = np.mean(iris_X[iris_y == cl], axis=0) # 计算每类样本均值 mean_vectors.append(class_mean_vector) # 存储均值向量 print(label_dict[cl], class_mean_vector) # 计算类内散布矩阵 S_W = np.zeros((4, 4)) # 初始类内散步矩阵 for cl, mv in zip([0, 1, 2], mean_vectors): # 从0开始,计算每个类别的散布矩阵 class_sc_mat = np.zeros((4, 4)) # 每个类别的散步矩阵 for row in iris_X[iris_y == cl]: # 访问该类的每个样本 row, mv = row.reshape(4, 1), mv.reshape(4, 1) # 列向量 class_sc_mat += (row-mv).dot((row-mv).T) # 4 x 4的矩阵 S_W += class_sc_mat # 散布矩阵的和 # 类计算间散布矩阵 overall_mean = np.mean(iris_X, axis=0).reshape(4, 1) # 数据集的均值 S_B = np.zeros((4, 4)) # 初始化类间散布矩阵 for i, mean_vec in enumerate(mean_vectors): n = iris_X[iris_y == i, :].shape[0] # 每种花的数量 mean_vec = mean_vec.reshape(4, 1) # 每种花的列向量 S_B += n * (mean_vec - overall_mean).dot((mean_vec - overall_mean).T) # 计算矩阵的特征值和特征向量 eig_vals, eig_vecs = np.linalg.eig(np.dot(np.linalg.inv(S_W), S_B)) eig_vecs = eig_vecs.real eig_vals = eig_vals.real for i in range(len(eig_vals)): eigvec_sc = eig_vecs[:,i] print('Eigenvector {}: {}'.format(i+1, eigvec_sc)) print('Eigenvalue {:}: {}'.format(i+1, eig_vals[i]))
得到四个特征值和四个特征向量
在项目中一般不会使用上面的方式一步一步的写过程,而直接调用sklearn中的接口实现LDA,上面的代码是为了更好的理解LDA的实现过程。
导入数据
X ,y = load_iris(return_X_y=True)
调用LDA并画出对比图
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis import matplotlib.pyplot as plt lda=LinearDiscriminantAnalysis(n_components=2) X_new_lda=lda.fit_transform(X,y) # 这是有监督的学习所以需要X,y plt.scatter(X[:,0],X[:,1],c=y) plt.figure() plt.scatter(X_new_lda[:,0],X_new_lda[:,1],c=y)
看特征值
lda.scalings_ # 特征向量 lda.explained_variance_ratio_ # 类似解释方差
可以看出第一个特征已经占数据全部信息的99%以上了
转换前后数据的分布以及判别式(特征向量)的分布
依然以鸢尾花数据为例,首先画原始数据集
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis from sklearn.datasets import load_iris import matplotlib.pyplot as plt import numpy as np X, y = load_iris(return_X_y=True) lda = LinearDiscriminantAnalysis(n_components=2) # 实例化LDA类 X_lda_iris = lda.fit_transform(X, y) # 拟合并转换鸢尾花数据 ''' # 下面的代码展示原始数据和用LDA投影后的数据 # 但是在图上,每个都按数据的向量处理 # 长箭头是第一个特征向量,短箭头是第二个 ''' iris_2_dim = X[:, 2:4] # 截取后两列数据 iris_2_dim = iris_2_dim - iris_2_dim.mean(axis=0) # 中心化 iris_2_dim_transformed_lda = lda.fit_transform(iris_2_dim, y) # 在截断的数据集上拟合 components = lda.scalings_.T # 转置为和PCA一样,行变成主成分 def draw_vector(v0, v1, ax): arrow_props = dict(arrowstyle='->', linewidth=2, shrinkA=0, shrinkB=0) ax.annotate('', v1, v0, arrowprops=arrow_props) fig, ax = plt.subplots(1, 1, figsize=(10, 10)) fig.subplots_adjust(left=0.0625, right=0.95, wspace=0.1, hspace=0.25) ax.scatter(iris_2_dim[:, 0], iris_2_dim[:, 1], alpha=0.2, c=y) for length, vector in zip(lda.explained_variance_ratio_, components): v = vector * np.sqrt(length) draw_vector(lda.xbar_, lda.xbar_ + v, ax=ax) # lda.xbar_ 等于 pca.mean_ ax.set(xlabel='x', ylabel='y', xlim=(-8, 8), ylim=(-3, 3), title='Original Iris Dataset') ax.grid()
lda转化后的
fig, ax = plt.subplots(1, 1, figsize=(10, 10)) ax.scatter(iris_2_dim_transformed_lda[:, 0], iris_2_dim_transformed_lda[:, 1], alpha=0.2, c=y) for length, vector in zip(lda.explained_variance_ratio_, components): transformed_component = lda.transform([vector])[0] v = transformed_component * np.sqrt(length) draw_vector(iris_2_dim_transformed_lda.mean(axis=0), iris_2_dim_transformed_lda.mean(axis=0) + v, ax=ax) ax.set(xlabel='lda component 1', ylabel='lda component 2', title='Linear Discriminant Analysis Projected Data', xlim=(-10, 10), ylim=(-3, 10)) ax.grid()
其实,横轴基本就可以把样本区分开,预测应该是垂直横轴,但是画图显示实际上还是并不完全垂直与横轴。PCA与方差的方向一致,LDA与方差的方向垂直。LDA是想要找到一个可以直接将样本分开的空间,而PCA是要找到可以将样本的信息也就是方差很好的区分开的空间
判别式基本垂直与方差的方向
解读LDA
注意判别式并不与数据的方差一致,而是基本与之垂直:符合类别的分离情况。
判别式与左右两侧鸢尾花之间的间隔几乎平行,LDA在试图捕捉两个类别的分离情况。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)