特征工程:LDA实例(实例)

特征工程:LDA实例(实例),第1张

特征工程:LDA实例(实例) 1.LDA工作流程及实现

线性判别分析(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]))

得到四个特征值和四个特征向量

2.sklearn实现LDA

在项目中一般不会使用上面的方式一步一步的写过程,而直接调用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%以上了

3.LDA数据分布探索

转换前后数据的分布以及判别式(特征向量)的分布
依然以鸢尾花数据为例,首先画原始数据集

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在试图捕捉两个类别的分离情况。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5701557.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-18
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存