LDA线性判别分析+KNN分类(含python实现代码)

以下使用数据集为:COIL20.mat(1440X1024)

下载链接:https://pan.baidu.com/s/13kXvS4elgHmuuttS8arFqA

提取码:rvyo


LDA介绍:

LDA是一种常用的数据降维方式,它属于监督式降维(特征提取)。通常在分类之前降低数据维度,使得不同类之间的数据更加的泾渭分明


 

原理解释:

基本原理将高维的样本数据投影到最佳判别向量空间,以达到特征提取(维数约简)的效果,投影后保证样本数据在新的子空间有最大的类间距离和最小的类内距离,即在该子空间中具有最佳的可分离性。

数学解释: 通过一个线性变换,R^{d}(n\times d为的矩阵)中的样本数据映射到R^{^{k}}(d维降到k),且希望该变换将属于同一类的样本映射得越近越好(即最小的类内距离),而将不同类的样本映射得越远越好 (即最大的类间距离)。同时还能尽能多地保留样本数据的判别信息。

我们所要做的就是找到一个线性变换,满足上述描述。

更加精确的描述就是:R^{k}=R^{k}\cdot w^{T} 显然 w应该是一个k\times d 的矩阵。保证矩阵n\times d \rightarrow n\times k


优化目标:

有了问题,我们就要知道如何让我们找到的答案越来越好。

先从简单的二分类问题出发:

我们尝试将二维点坐标映射到一条直线上,显然我们要选择右图中的映射方式:

  • 映射后,不同类之间有着明显的分界
  • 同类型数据分布更加紧凑

我们尝试找出两个数学表达表达上述两种条件。

设置两类样本集合X_{1},X_{2},分别对应样本均值\mu _{1},\mu_{2}   \mu_{i}=\frac{1}{N_{i}} \sum_{x \in X_{i}} x

\mu _{1},\mu_{2}经过线性变化后,得到映射到直线上的\overline{z_{1}}, \overline{z_{2}}。(\overline{z_{i}}=\mu_{i} \bullet w^{T}=\frac{1}{N_{i}} \sum_{x \in X_{i}} x \bullet w^{T})

这样我们可以将两类中心之间的距离近似看为类间距离。

  • \overline{z_{1}}, \overline{z_{2}}之间距离越大越好(类间离散度)

             J_{b}=\left\|\overline{z}_{1}-\overline{z}_{2}\right\|

同样我们要求类内距离小(同类数据方差小)

  • Z_{i}内数据集中在\overline{z_{i}}附近(类内离散度)

           J_{w}=s_{1}^{2}+s_{2}^{2},其中s_{i}=\sum_{z \in Z_{i}}\left(z-\overline{z}_{i}\right)^{2}

所以最后的优化目标函数是:

           \arg \max _{w} J(w)=\frac{J_{b}}{J_{w}}=\frac{\left|\overline{z}_{1}-\overline{z}_{2}\right|}{s_{1}^{2}+s_{2}^{2}}


更进一步的化简:

\begin{array}{l}{J_{b}=\left|\overline{z}_{1}-\overline{z}_{2}\right|=\left|w^{T}\left(\mu_{1}-\mu_{2}\right)\right| \Rightarrow} {w^{T}\left(\mu_{1}-\mu_{2}\right)\left(\mu_{1}^{T}-\mu_{2}^{T}\right) w \triangleq w^{T} S_{b} w}\end{array}

注:多分类下,S_{b}=\sum_{i=1}^{N}\left(\mu_{i}-\mu\right)\left(\mu_{i}-\mu\right)^{T}\mu是总体均值

{J_{w}=s_{1}^{2}+s_{2}^{2}=\sum_{i=1}^{2} \sum_{z \in Z_{i}}\left(z-w^{T} \mu_{i}\right)=\sum_{i=1}^{2} \sum_{x \in X_{i}} w^{T}\left(x-\mu_{i}\right)\left(x-\mu_{i}\right)^{T} w} \\ ={w^{T}\left(\sum_{i=1}^{2} \sum_{x \in X_{i}}\left(x-\mu_{i}\right)\left(x-\mu_{i}\right)^{T}\right) w \triangleq w^{T} S_{w} w}

 

最终转化为:\underset{w}{\arg \max } J(w)=\frac{J_{b}}{J_{w}}=\frac{w^{T} S_{b} w}{w^{T} S_{w} w}

...

更详细的化简可以翻阅《模式识别》一书中的LDA线性判别分析。

最终化简为:

S_{w}^{-1} S_{b} w=\lambda w(这是在可逆的情况下)。

如果矩阵不可逆,可为奇异矩阵加上一个单位矩阵,单位矩阵乘以一个很小的系数,如0.001)

结论:最优w就是的S_{w}^{-1} S_{b}特征向量矩阵,而这个公式也称为Fisher线性判别

注意:如果我们要求d维降到k维,则我们的w是S_{w}^{-1} S_{b}最大的k个特征向量构成的矩阵。

也许,你求出的w矩阵是复数矩阵,那么取w得实部。


代码实现:

# -*- coding: utf-8 -*-
"""
Created on Wed May 15 14:48:32 2019
Python 3.6.8
@author: yh
"""
from numpy import linalg as LA
from scipy import io
import numpy as np
import matplotlib.pyplot as plt
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import train_test_split
import tensorflow as tf
"""
LDA线性判别分析
数据降维+KNN分类

"""

np.random.seed(0) 
"""
导入数据
这个数据集1400X1024
20X72
20中类别,每类72个32x32的灰度图像
"""
data=io.loadmat('COIL20.mat')
x=data['fea']
y=data['gnd']


def Std(Sw):
    u=np.mean(Sw)
    s=np.std(Sw)
    Sw=(Sw-u)/s
    return Sw

#X是数据集,k是降到k维,n是数据集中类的个数,m是每一个样本的维度
def Fisher(X,k,n,m):
    #求每一类的均值
    mu=np.zeros((n,1,m))
    for i in range(n):
        for j in range(len(X[i])):
            mu[i]=mu[i]+X[i][j]
        mu[i]=mu[i]/len(X[i])
    #总体均值
    u=np.mean(mu,axis=0)
    Sw=np.zeros((m,m))
    Sb=np.zeros((m,m))
    for i in range(n):
        for j in range(len(X[i])):
            #注意np.dot才是矩阵乘法,‘*’对于array来说是点乘
            Sw=Sw+np.dot((X[i][j]-mu[i]).T,(X[i][j]-mu[i]))
    for i in range(n):
        Sb=Sb+np.dot((mu[i]-u).T,(mu[i]-u))
    #单位矩阵
    I=np.identity(m)
    #归一化
    Sw=Std(Sw);
    Sw=Sw+0.000000001*I
    val,vec=np.linalg.eig(np.dot(np.mat(Sw).I ,Sb))
    #求最大K个特征向量编号
    index=np.argsort(-val)
    #最大K个特征向量所组成的矩阵
    w=vec[index[0:k]]
    #取w矩阵实部返回
    return w.real

    

def Class_KNN(X,Y):
    #KNN分类
    #自动分出训练集,测试集
    x_train,x_test,y_train,y_test = train_test_split(X,Y)
    knn = KNeighborsClassifier() 
    knn.fit(x_train,y_train.ravel())
    accuracy=knn.score(x_test,y_test,sample_weight=None)
    return accuracy
    

def Showimage(X,x,n,m):
    ###这里可以修改最大降维维度
    k=100
    K=np.arange(1,k)
    Ac=np.zeros((1,k-1))
    print(K.shape,Ac.shape)
    for i in range(len(K)):
        w=Fisher(X,K[i],n,m)
        z=np.dot(x,w.T)
        Ac[0][i]=Class_KNN(z,y)
    #画出k-ac图片
    plt.plot(K,Ac.ravel(),'-r')
    plt.xlabel('K-Dimesions')
    plt.ylabel('Accuracy')


if __name__=="__main__":
        n,m=x.shape
        print(n,m)
        X=np.zeros((n//72,72,m))
        for i in range(n//72):
            xi=x[i*72:i*72+72,:]
            X[i]=xi
        Showimage(X,x,n//72,m)
    
            

 


结果展示:


 

  • 5
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
LDA(Linear Discriminant Analysis) 线性判别分析是一种常用的机器学习算法,主要用于分类任务。下面是Python实现LDA线性判别分析的示例代码: ```python import numpy as np from sklearn.preprocessing import StandardScaler class LDA: def __init__(self, n_components): self.n_components = n_components self.linear_discriminants = None def fit(self, X, y): n_features = X.shape[1] class_labels = np.unique(y) # 计算各类别均值向量 mean_overall = np.mean(X, axis=0) mean_class = np.zeros((len(class_labels), n_features)) for c in class_labels: X_c = X[y == c] mean_class[c] = np.mean(X_c, axis=0) # 计算类内散度矩阵 within_class_scatter = np.zeros((n_features, n_features)) for c in class_labels: X_c = X[y == c] cov = (X_c - mean_class[c]).T.dot(X_c - mean_class[c]) within_class_scatter += cov # 计算类间散度矩阵 between_class_scatter = np.zeros((n_features, n_features)) for c in class_labels: n_c = X[y == c].shape[0] mean_c = mean_class[c].reshape(n_features, 1) mean_overall = mean_overall.reshape(n_features, 1) between_class_scatter += n_c * (mean_c - mean_overall).dot((mean_c - mean_overall).T) # 计算投影矩阵 eigen_values, eigen_vectors = np.linalg.eig(np.linalg.inv(within_class_scatter).dot(between_class_scatter)) eigen_vectors = eigen_vectors.T idxs = np.argsort(abs(eigen_values))[::-1] eigen_vectors = eigen_vectors[idxs] self.linear_discriminants = eigen_vectors[0:self.n_components] def transform(self, X): return np.dot(X, self.linear_discriminants.T) ``` 以上代码使用了NumPy和Scikit-learn库,其中fit()方法用于拟合模型,transform()方法用于将数据投影到LDA的特征向量上。需要注意的是,在使用LDA之前应该对数据进行标准化处理,以避免数值计算上的不稳定性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值