您的位置:

线性判别分析(Linear Discriminant Analysis)

一、算法概述

线性判别分析(Linear Discriminant Analysis,LDA)是常用的一种分类算法。它是一种有监督学习方法,也就是需要已知每个样本的类别标签。LDA从特征空间中提取线性判别信息,用于在低维空间中对数据进行分类。

LDA的主要思想是:将样本投影到一条直线上,使得同类之间的距离尽可能小,不同类之间的距离尽可能大。因此,LDA在降维同时也完成了分类任务。

二、算法流程

LDA的算法流程如下:

  1. 计算每个类别的均值向量。
  2. 计算类间散度矩阵和类内散度矩阵。
  3. 求出最大化目标函数的投影方向。
  4. 降维并进行分类。

三、算法实现

第一步:计算均值向量

设有样本集$D={x_1, x_2, ..., x_n}$,其中$x_i\in R^d$表示第$i$个样本。将样本按照类别分开,设有$k$个类别。第$i$类样本的个数为$n_i$,均值向量为$u_i$。

import numpy as np

def mean_vectors(X, y):
    class_labels = np.unique(y)
    n_classes = class_labels.shape[0]
    mean_vectors = np.zeros((n_classes, X.shape[1]))
    for cl, label in enumerate(class_labels):
        mean_vectors[cl,:] = np.mean(X[y==label], axis=0)
    return mean_vectors

第二步:计算类间散度矩阵和类内散度矩阵

类间散度矩阵$S_B$和类内散度矩阵$S_W$的计算方式如下:

$$S_B = \sum_{i=1}^{k}n_i(u_i - u)(u_i - u)^T$$ $$S_W = \sum_{i=1}^{k}\sum_{x\in D_i}(x-u_i)(x-u_i)^T$$ 其中,$u$为所有样本的均值向量,$S_B$表示类别之间的差异,$S_W$表示类别内部的差异。
def scatter_matrices(X, y):
    mean_vectors = mean_vectors(X, y)
    n_features = X.shape[1]
    s_within = np.zeros((n_features, n_features))
    s_between = np.zeros((n_features, n_features))
    mean_overall = np.mean(X, axis=0)
    for cl, mv in enumerate(mean_vectors):
        class_sc_mat = np.zeros((n_features, n_features))
        for row in X[y == cl]:
            row, mv = row.reshape(n_features, 1), mv.reshape(n_features, 1)
            class_sc_mat += (row - mv).dot((row - mv).T)
        s_within += class_sc_mat        
        n = X[y==cl,:].shape[0]
        mean_diff = (mv - mean_overall).reshape(n_features, 1)
        s_between += n * mean_diff.dot(mean_diff.T)
    return s_within, s_between

第三步:求投影方向

为了求出最大化目标函数的投影方向,需要计算矩阵$S_W^{-1}S_B$的特征向量和特征值。在计算投影矩阵的时候,我们可以取最大的$d'$个特征向量($d'$表示投影后保留的维数)。

def lda(X, y, n_components):
    s_within, s_between = scatter_matrices(X, y)
    eig_vals, eig_vecs = np.linalg.eig(np.linalg.inv(s_within).dot(s_between))
    eig_pairs = [(np.abs(eig_vals[i]), eig_vecs[:,i]) for i in range(len(eig_vals))]
    eig_pairs = sorted(eig_pairs, key=lambda k: k[0], reverse=True)
    proj_mat = eig_pairs[0][1].reshape(X.shape[1],1)
    for i in range(1,n_components):
        proj_mat = np.hstack((proj_mat, eig_pairs[i][1].reshape(X.shape[1],1)))
    return X.dot(proj_mat), proj_mat

第四步:降维并进行分类

使用投影矩阵将样本投影到新的低维空间中,并使用分类算法进行分类。下面的例子中,我们使用支持向量机作为分类器。

from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn.svm import SVC

iris = datasets.load_iris()
X = iris.data
y = iris.target
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)

X_train_lda, proj_mat = lda(X_train, y_train, 2)
X_test_lda = X_test.dot(proj_mat)

classifier = SVC()
classifier.fit(X_train_lda, y_train)
score = classifier.score(X_test_lda, y_test)
print("Accuracy:", score)

四、总结

LDA作为一种常用的分类算法,在特征提取和降维方面有着广泛的应用。通过计算均值向量和散度矩阵,我们可以求出最大化目标函数的投影方向,从而实现对数据的降维和分类。