哈喽,我是小白~
本篇文章给大家带来的是关于线性判别分析LDA的内容~
线性判别分析(LDA)是一种用于分类的监督学习方法,旨在通过寻找投影方向将数据投影到低维空间,以最大化类间差异与类内一致性。它最初由 Ronald A. Fisher 提出,因此也称为 Fisher判别分析。
LDA 的主要目标是在保留数据区分信息的同时,减少特征的维度。这一方法通过将数据映射到低维空间,实现了降维与分类的双重目的。
LDA 适用于以下场景:
样本服从高斯分布。 特征之间线性可分。
LDA 基本原理
LDA 的目标是寻找线性投影,使得投影后的数据在类间尽可能分开,而在类内尽可能紧密。具体来说,LDA 通过最大化类间协方差矩阵和最小化类内协方差矩阵之间的比值来实现这一目的。
类内和类间协方差矩阵
设有 个类别的数据,每一类数据记为 ,其中 ,表示第 类的 个样本,特征维度为 。
类内协方差矩阵 :
反映了同一类数据的离散程度,定义为:
其中, 是第 类的均值向量,。
类间协方差矩阵 :
反映了不同类数据之间的分离程度,定义为:
其中, 是总体数据的均值向量,, 是总样本数。
Fisher 判别准则
LDA 的目标是通过投影向量 将数据映射到一维空间,使得投影后类间方差与类内方差的比值最大化。这可以通过 Fisher 判别准则来表达:
最大化 的最优解是 的特征向量。根据特征值的大小排序,前 个特征向量构成了线性判别投影空间,其中 是类别数。
LDA 计算步骤
计算每个类别的均值向量。
计算类内协方差矩阵和类间协方差矩阵。
求解广义特征值问题:
其中, 是特征值, 是特征向量。
选择前 个特征向量作为新的投影方向。
将数据投影到新空间,进行分类。
案例实现
我们生成两个类的二维数据集,每类的数据分布为高斯分布,且两类存在较大重叠,确保问题具有一定的挑战性。
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_classification
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA
from sklearn.model_selection import train_test_split
# 生成虚拟数据集
X, y = make_classification(n_samples=1000, n_features=2, n_informative=2, n_redundant=0, n_classes=2, n_clusters_per_class=1, class_sep=1.5, random_state=42)
# 分割数据集为训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
# 绘制数据分布
plt.figure(figsize=(8, 6))
plt.scatter(X_train[y_train==0][:, 0], X_train[y_train==0][:, 1], color='blue', label='Class 0')
plt.scatter(X_train[y_train==1][:, 0], X_train[y_train==1][:, 1], color='red', label='Class 1')
plt.title("Scatter plot of the training data")
plt.xlabel('Feature 1')
plt.ylabel('Feature 2')
plt.legend()
plt.show()
可以看到,数据点被分成了两类,但两类之间存在重叠。这为分类任务增加了难度。
LDA 模型训练
我们使用 sklearn
库中的 LDA 来训练模型,并可视化数据投影到一维后的结果。
# 初始化LDA模型并进行训练
lda = LDA()
lda.fit(X_train, y_train)
# 将数据投影到一维空间
X_train_lda = lda.transform(X_train)
X_test_lda = lda.transform(X_test)
# 绘制训练集在LDA方向上的投影
plt.figure(figsize=(8, 6))
plt.hist(X_train_lda[y_train==0], bins=20, color='blue', alpha=0.7, label='Class 0')
plt.hist(X_train_lda[y_train==1], bins=20, color='red', alpha=0.7, label='Class 1')
plt.title("LDA projection of the training data")
plt.xlabel('LDA component')
plt.ylabel('Frequency')
plt.legend()
plt.show()
图中显示了训练数据投影到 LDA 方向上的分布。可以看到,尽管两类数据的投影有所重叠,但 LDA 成功地将它们在一维空间中尽可能分离开。
模型预测与评估
接下来,我们使用测试集来评估 LDA 模型的分类效果。
from sklearn.metrics import accuracy_score, confusion_matrix, classification_report
# 使用测试集进行预测
y_pred = lda.predict(X_test)
# 输出分类报告与混淆矩阵
print("Classification Report:\n", classification_report(y_test, y_pred))
print("Confusion Matrix:\n", confusion_matrix(y_test, y_pred))
# 绘制测试数据的散点图以及决策边界
plt.figure(figsize=(8, 6))
plt.scatter(X_test[y_test==0][:, 0], X_test[y_test==0][:, 1], color='blue', label='Class 0')
plt.scatter(X_test[y_test==1][:, 0], X_test[y_test==1][:, 1], color='red', label='Class 1')
# 绘制决策边界
coef = lda.coef_[0]
intercept = lda.intercept_
x_values = np.linspace(X_test[:, 0].min(), X_test[:, 0].max(), 100)
y_values = -(coef[0] * x_values + intercept) / coef[1]
plt.plot(x_values, y_values, color='black', linestyle='--', label='Decision Boundary')
plt.title("LDA Decision Boundary on Test Data")
plt.xlabel('Feature 1')
plt.ylabel('Feature 2')
plt.legend()
plt.show()
我们可以看到,LDA 模型在测试数据上的决策边界基本上正确地将两类数据分开。虽然部分数据点在决策边界的错误侧,但总体上分类效果良好。
其中:
图 1 (训练数据的散点图): 该图展示了数据集的初始分布情况,蓝色和红色点分别代表两类数据。可以看到,类间数据存在部分重叠,因此分类问题具有一定难度。
图 2 (LDA 投影图): 该图显示了数据经过 LDA 线性投影后在一维空间的分布。通过 Fisher 判别准则,LDA 将两类数据投影到尽可能分离的方向上。我们可以看到,尽管类间仍有部分重叠,但总体上类间分离较好。
图 3 (测试数据的决策边界图): 该图展示了 LDA 模型在测试数据上的决策边界。黑色虚线代表决策边界,模型通过该边界将两类数据尽可能正确地分开。少数点被错误分类,显示了模型的局限性,但总体表现良好。
线性判别分析的优势与局限性
优势
易解释性: LDA 提供了清晰的线性投影方向,使得我们可以通过权重向量理解每个特征在分类中的作用。 降维能力: 在多类别情况下,LDA 可将数据降维到 维空间,这对于高维数据尤为有用。 计算简单: LDA 通过矩阵运算实现,计算效率高。
局限性
数据分布假设: LDA 假设数据服从正态分布,且各类别具有相同的协方差矩阵。当这一假设不成立时,模型效果可能不佳。 线性可分性: LDA 的核心是寻找线性边界,当数据非线性可分时,LDA 的表现可能不如其他非线性模型。 对异常值敏感: LDA 对数据中的异常值较为敏感,可能导致决策边界偏移。
最后
线性判别分析(LDA)是一种经典的降维与分类算法,它通过最大化类间散布与最小化类内散布来寻找最佳线性投影方向。在实际应用中,LDA 具有良好的可解释性和计算效率,适用于许多高维分类问题。然而,LDA 的表现依赖于数据的分布形式,因此在处理非线性数据时需要结合其他方法进行扩展(如核 LDA)。