跳至主要内容

线性判别分析:不仅仅是降维

了解 LDA 如何在降维的同时优化类别分离,以助力您的机器学习项目。
· 9分钟 阅读

使用 AI 探索

在降维领域,线性判别分析(LDA)常常被更为流行的主成分分析(PCA)所掩盖。然而,LDA 提供了 PCA 无法做到的独特能力:它在降维的同时优化类别可分性。

本教程将向您介绍 LDA、其背后的数学直觉以及该技术的实际应用。我们还将把 LDA 应用于一个数据集,与 PCA 进行比较,分析其优劣势,旨在为您提供在下一个项目中开始使用 LDA 所需的一切。

线性判别分析(LDA)简介

在假设不同类别的数据分别来自不同的高斯分布的前提下,LDA 是一种降维与分类技术。 

LDA 的目标是找到能最好地区分这些类别的特征线性组合。它最大化类间散度与类内散度的比值。通俗地说,它试图在特征空间中找到使不同类别彼此相距更远(高类间散度)、同一类别内部点彼此更接近(低类内散度)的方向。 

这种双重目标使 LDA 在降维与分类任务中都格外有效。

LDA 背后的数学

理解 LDA 的数学原理需要将算法分解为三个关键组成部分: 

  • 类内散度, 
  • 类间散度,以及
  • 优化目标。

类内散度矩阵(Sw)

类内散度矩阵衡量每个类别内部数据点的分散程度。 

对于每个类别i,我们计算散度矩阵 Si 为:

Si = Σ(x - μi)(x - μi)T

其中 x 表示类别 i 中的每个数据点,μi 是类别 i 的均值。总的类内散度矩阵为:

Sw = Σ Si (sum over all classes)

类间散度矩阵(Sb)

类间散度矩阵衡量各类别均值与整体均值之间的距离。其计算方式为:

Sb = Σ Ni(μi - μ)(μi - μ)T  

其中 Ni 是类别 i 的样本数,μi 是类别 i 的均值,μ 是所有数据的整体均值。

优化目标

LDA 旨在找到使 Fisher 准则最大化的投影矩阵 W:

J(W) = |WT Sb W| / |WT Sw W|

本质上,这是在投影空间中最大化类间散度与类内散度之比。其解涉及求矩阵 Sw-1Sb 的特征向量,即得到最佳区分类别的方向(线性判别向量)。

因此,LDA 将这一复杂的优化问题转化为特征值分解,从而在中等高维数据集上也具有计算效率。

在理解了 LDA 的概念与数学直觉后,接下来看看它的实际应用。

LDA 的真实世界应用

在需要分类与降维的多个领域,LDA 都有所应用:

  • 医学诊断:LDA 用于医学影像中对不同类型的肿瘤或异常进行分类。它可以分析 MRI 扫描,通过识别图像数据中最具判别性的特征来区分良性与恶性组织。
  • 金融与银行:信用评分系统使用 LDA 将贷款申请人划分为不同风险类别。通过分析收入、负债收入比、信用历史等财务指标,LDA 可帮助区分高风险与低风险借款人。
  • 生物信息学:基因表达分析使用 LDA 对不同疾病状态或治疗反应进行分类。它有助于识别在区分健康与患病组织样本中最重要的基因。
  • 市场营销与客户细分:企业使用 LDA 基于购买行为、人口统计数据与参与度指标对客户进行细分,这在目标营销活动和个性化产品推荐中非常有用。
  • 图像识别:人脸识别系统利用 LDA 在保留最有助于区分不同个体的特征的同时,降低人脸图像的维度。
  • 质量控制:制造业基于各种质量指标应用 LDA 将产品分类为次品或合格品,从而实现自动化质保流程。
  • 语音识别:LDA 通过识别最能区分不同语音音素的声学特征来辅助音素分类,从而提升语音转文本系统的准确率。
  • 环境监测:LDA 被用于基于传感器数据对环境状况进行分类,例如区分不同的污染水平或天气模式。

在 Python 中实现 LDA

让我们通过一个端到端示例,使用 Python 实现 LDA。 

我们将使用 Seeds 数据集,可从UCI 库以及Kaggle下载。该数据集包含属于三种不同小麦品种的小麦籽粒测量值。 

步骤 1:导入库并加载数据

首先,我们导入必要的库并加载数据集:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
from sklearn.metrics import classification_report, confusion_matrix, accuracy_score

# Load the seeds dataset
file_path = "seeds_dataset.txt"
column_names = ['area', 'perimeter', 'compactness', 'kernel_length',
               'kernel_width', 'asymmetry', 'groove_length', 'variety']

# Read the data with whitespace delimiter (space or tab)
seeds_df = pd.read_csv(file_path, sep='\s+', header=None, names=column_names)

print(f"Dataset shape: {seeds_df.shape}")
seeds_df.head()

我们将在下方查看已加载数据集的前 5 行:

Seeds 数据集概览。Seeds 数据集概览。(作者供图)

步骤 2:数据预处理

探索数据结构并为 LDA 分析做准备:

# Check for missing values
print(f"Missing values: {seeds_df.isnull().sum().sum()}")

# Check class distribution
print("\nClass distribution:")
print(seeds_df['variety'].value_counts())

# Separate features and target
X = seeds_df.drop('variety', axis=1)
y = seeds_df['variety']

# Split the data into training and testing sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3,
                                                   random_state=42, stratify=y)

# Standardize the features
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

这里我们检查数据集中是否存在缺失值,并查看每个类别包含多少样本。随后通过将输入与标签分离、划分训练集与测试集,并对输入值进行标准化,使所有特征处于相近量纲,为后续建模做准备。

数据预处理。

数据预处理。(作者供图)

可以看到不存在缺失值,且类别分布均衡。

步骤 3:应用 LDA 进行降维

现在我们将应用 LDA,在保留类别可分性的同时降低数据维度:

# Create and fit LDA model
lda = LinearDiscriminantAnalysis(n_components=2)
X_train_lda = lda.fit_transform(X_train_scaled, y_train)
X_test_lda = lda.transform(X_test_scaled)

# Print explained variance ratio
print("Explained variance ratio:", lda.explained_variance_ratio_)
print("Cumulative explained variance:", np.cumsum(lda.explained_variance_ratio_))

我们创建一个模型来寻找最佳方向,以分离数据中的不同类别。由于有三个类别,将数据降至两个新特征,可以保留区分它们的最重要模式。

输出如下:

LDA 方差结果。LDA 方差结果。(作者供图)

该输出展示了由 LDA 生成的两个新特征分别捕获了多少类别分离信息:

  • 解释方差比:这意味着第一个 LDA 分量捕获了约 67.7% 的类别区分信息,而第二个分量捕获了剩余的 32.3%。
  • 累积解释方差:两个分量合计捕获了原始数据中 100% 的类别分离信息。这是预期的,因为我们有 3 个类别,而 LDA 至多给出 2 个有用方向。

步骤 4:可视化 LDA 变换

让我们可视化 LDA 如何变换数据并分离各类别:

fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 6))

# Plot the first two original features
ax1.scatter(X_train_scaled[:, 0], X_train_scaled[:, 1],
           c=y_train, cmap='viridis', alpha=0.7, edgecolor='k')
ax1.set_xlabel('Area (standardized)')
ax1.set_ylabel('Perimeter (standardized)')
ax1.set_title('Original Feature Space (First Two Features)')
ax1.grid(True, alpha=0.3)

# Plot LDA-transformed data
scatter = ax2.scatter(X_train_lda[:, 0], X_train_lda[:, 1],
                     c=y_train, cmap='viridis', alpha=0.7, edgecolor='k')
ax2.set_xlabel('First Linear Discriminant')
ax2.set_ylabel('Second Linear Discriminant')
ax2.set_title('LDA-Transformed Space')
ax2.grid(True, alpha=0.3)

plt.colorbar(scatter, ax=ax2, label='Wheat Variety')
plt.tight_layout()
plt.show()

上述代码创建了两个并排的图表,帮助我们对比应用降维技术前后数据的变化,如下所示:

LDA 可视化。LDA 可视化。(作者供图)

第一个图使用两项原始测量特征(面积与周长)展示数据,以观察类别在原空间中的天然分离程度。第二个图展示了将数据变换到最有利于类别分离的方向后的结果。我们添加了颜色条来指示不同颜色对应的小麦品种。

步骤 5:将 LDA 用于分类

LDA 也可以直接作为分类器使用。 

让我们来实现它:

# Create LDA classifier
lda_classifier = LinearDiscriminantAnalysis()
lda_classifier.fit(X_train_scaled, y_train)

# Make predictions
y_pred = lda_classifier.predict(X_test_scaled)

# Calculate accuracy
accuracy = accuracy_score(y_test, y_pred)
print(f"Classification Accuracy: {accuracy:.4f}")

# Print classification report
print("\nClassification Report:")
print(classification_report(y_test, y_pred))

我们根据训练数据训练一个模型来识别不同的小麦类别。随后在新的、未见过的样本上测试其表现,通过总体准确率以及对各类别的预测情况来评估。

输出如下:

LDA 分类结果。

LDA 分类结果。(作者供图)

该模型对小麦类型的预测准确率约为 92%,可视为表现良好。 

该示例表明,尽管 LDA 常用于降维,但它也可以通过对各类别的概率分布进行建模,并将新数据分配给似然最高的类别,从而充当分类器。

用代码与可视化对比 LDA 与 PCA

主成分分析是另一种流行的降维技术,旨在寻找数据中方差最大的方向。 

让我们在前面示例的基础上比较 LDA 与 PCA:

from sklearn.decomposition import PCA

# Apply PCA with 2 components
pca = PCA(n_components=2)
X_train_pca = pca.fit_transform(X_train_scaled)
X_test_pca = pca.transform(X_test_scaled)

# Create comparison visualization
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 6))

# Plot PCA results
scatter1 = ax1.scatter(X_train_pca[:, 0], X_train_pca[:, 1],
                      c=y_train, cmap='viridis', alpha=0.7, edgecolor='k')
ax1.set_xlabel('First Principal Component')
ax1.set_ylabel('Second Principal Component')
ax1.set_title(f'PCA Transformation\nExplained Variance: {pca.explained_variance_ratio_.sum():.2%}')
ax1.grid(True, alpha=0.3)

# Plot LDA results
scatter2 = ax2.scatter(X_train_lda[:, 0], X_train_lda[:, 1],
                      c=y_train, cmap='viridis', alpha=0.7, edgecolor='k')
ax2.set_xlabel('First Linear Discriminant')
ax2.set_ylabel('Second Linear Discriminant')
ax2.set_title(f'LDA Transformation\nExplained Variance: {lda.explained_variance_ratio_.sum():.2%}')
ax2.grid(True, alpha=0.3)

plt.colorbar(scatter1, ax=ax1, label='Wheat Variety')
plt.colorbar(scatter2, ax=ax2, label='Wheat Variety')
plt.tight_layout()
plt.show()

我们得到如下图:

LDA 与 PCA 对比。LDA 与 PCA 对比。(作者供图)

左图展示使用 PCA 后的数据,它寻找的是捕获数据整体方差最大的方向。右图展示使用 LDA 的结果,它寻找的是最能区分小麦类别的方向。

基于我们的实现结果与解释方差数值,可以得出结论:尽管两者表现都不错,但对这样的分类问题而言,LDA 通常能产生更清晰的群组分离。

LDA 与其他降维技术的显著区别在于其监督式特性。PCA 在不考虑类别标签的情况下仅关注数据方差,而 LDA 明确利用类别信息寻找最具判别力的方向。当处理高维数据且类别可分性比保留整体方差更重要时,这一点尤为理想。

因此,PCA 适用于以下情形:

  • 需要无监督的降维
  • 类别标签不可用或不相关
  • 希望可视化高维数据
  • 需要降低噪声与计算复杂度

类似地,LDA 适用于:

  • 拥有带标签数据并希望最大化类别分离
  • 每个类别的样本量充足(通常 > 30)
  • 同时需要降维与分类
  • 类别判别性比保留整体方差更重要

LDA 的优缺点

与任何算法一样,LDA 也有其优点与局限性,在项目中应用前需要加以权衡。

优点

  • 监督学习优势:不同于 PCA,LDA 使用类别标签信息来寻找最具判别性的特征,更适合分类任务。
  • 降维与分类二合一:既能降维,又提供内置分类器。
  • 计算高效:仅需进行特征值分解,对中等规模数据集也较为快速。
  • 可解释性强:线性判别向量可解释为原始特征的加权组合。
  • 对高斯分布最优:当各类别服从具有相同协方差矩阵的高斯分布时,提供最优线性分类器。
  • 无需超参数调优:与许多机器学习算法不同,基础实现的 LDA 无需调整超参数。

缺点

  • 仅限线性边界:无法捕捉特征与类别之间的非线性关系。
  • 高斯与等协方差假设:假设每个类别服从多元高斯分布,这在真实数据中未必成立;并假设所有类别具有相同的协方差矩阵,而实践中常被违背。
  • 分量数受限:至多可提取(n_classes — 1)个判别分量,对于多类别问题的可视化可能不足。
  • 对离群点与多重共线性敏感:均值与协方差的计算对离群点敏感;当特征高度相关时,算法表现可能不佳。
  • 样本量要求:需要每个类别有足够样本,才能可靠地估计协方差矩阵。

理解这些权衡能帮助我们判断 LDA 是否是手头问题的最佳选择。

结论

本文介绍了线性判别分析,这是一种通过最大化类间与类内散度之比,将降维与分类相结合的监督式技术。

我们探讨了 LDA 的数学基础,使用 Python 实现了该方法,并与 PCA 进行了比较,以了解各自更适用的场景。我们还了解了 LDA 的实际应用,并讨论了它的优点与局限。

若想进一步加深对 LDA 及相关机器学习技术的理解,建议报名我们的Python 监督式机器学习学习路径,系统掌握多种算法及其实现;或参加我们的Python 中的降维课程,更深入学习监督与无监督的降维技术。

Arunn Thevapalan

作者

Arunn Thevapalan

作为一名高级数据科学家,我设计、开发并部署大规模机器学习解决方案,帮助企业做出更明智的数据驱动决策。作为数据科学写作者,我分享所学心得、职业建议以及深入的实践型教程。

主题