线性判别分析(Linear Discriminant Analysis, LDA)详解

线性判别分析(Linear Discriminant Analysis, LDA)详解

1. 引言

线性判别分析(LDA)是一种经典的降维方法和分类方法,它在模式识别、机器学习等领域有着广泛应用。LDA的核心思想是:将高维数据投影到低维空间中,使得同类数据尽可能紧凑,不同类数据尽可能分开。

2. 数学原理

2.1 基本思想

LDA的目标是找到一个投影方向 w w w,使得:

  1. 同类样本投影后尽可能近(类内方差最小)
  2. 不同类样本投影后尽可能远(类间方差最大)

2.2 数学推导

对于二分类问题:

  1. 类内散度矩阵 S w S_w Sw
    S w = ∑ i = 1 c ∑ x ∈ X i ( x − μ i ) ( x − μ i ) T S_w = \sum_{i=1}^c \sum_{x \in X_i} (x - \mu_i)(x - \mu_i)^T Sw=i=1cxXi(xμi)(xμi)T

  2. 类间散度矩阵 S b S_b Sb
    S b = ∑ i = 1 c N i ( μ i − μ ) ( μ i − μ ) T S_b = \sum_{i=1}^c N_i(\mu_i - \mu)(\mu_i - \mu)^T Sb=i=1cNi(μiμ)(μiμ)T

  3. 目标函数(Fisher准则):
    J ( w ) = w T S b w w T S w w J(w) = \frac{w^T S_b w}{w^T S_w w} J(w)=wTSwwwTSbw

  4. 最优解:
    S w − 1 S b w = λ w S_w^{-1}S_b w = \lambda w Sw1Sbw=λw

3. 算法实现

import numpy as np
from sklearn.datasets import make_classification
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.metrics import confusion_matrix, classification_report
from sklearn.model_selection import train_test_split

class LDA:
    def __init__(self, n_components=1):
        self.n_components = n_components
        self.w = None
        self.explained_variance_ratio_ = None
        
    def fit(self, X, y):
        n_samples, n_features = X.shape
        classes = np.unique(y)
        
        # 计算类内散度矩阵
        S_w = np.zeros((n_features, n_features))
        for cls in classes:
            X_cls = X[y == cls]
            mean_cls = X_cls.mean(axis=0)
            X_centered = X_cls - mean_cls
            S_w += X_centered.T @ X_centered
            
        # 计算类间散度矩阵
        mean_total = X.mean(axis=0)
        S_b = np.zeros((n_features, n_features))
        for cls in classes:
            X_cls = X[y == cls]
            mean_cls = X_cls.mean(axis=0)
            n_cls = X_cls.shape[0]
            mean_diff = (mean_cls - mean_total).reshape(-1, 1)
            S_b += n_cls * mean_diff @ mean_diff.T
            
        # 求解特征值和特征向量
        eigvals, eigvecs = np.linalg.eig(np.linalg.inv(S_w) @ S_b)
        
        # 选择最大的n_components个特征值对应的特征向量
        idx = eigvals.argsort()[::-1]
        self.w = eigvecs[:, idx[:self.n_components]]
        
        # 计算解释方差比
        self.explained_variance_ratio_ = np.real(eigvals[idx[:self.n_components]] / np.sum(eigvals))
        
    def transform(self, X):
        return X @ self.w
    
    def predict(self, X):
        # 添加预测方法
        X_transformed = self.transform(X)
        # 使用简单的阈值进行分类(针对二分类问题)
        return (X_transformed[:, 0] > 0).astype(int)

4. 实验示例

# 数据准备
X, y = make_classification(n_samples=1000, n_features=20, n_classes=2, 
                         n_informative=2, n_redundant=10, random_state=42)

# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)

# 创建并训练LDA模型
lda = LDA(n_components=2)
lda.fit(X_train, y_train)

# 转换数据
X_train_transformed = lda.transform(X_train)
X_test_transformed = lda.transform(X_test)

# 1. 绘制训练集和测试集的投影结果
plt.figure(figsize=(15, 5))
plt.subplot(121)
plt.scatter(X_train_transformed[y_train==0, 0], X_train_transformed[y_train==0, 1], 
           c='red', label='Class 0', alpha=0.7)
plt.scatter(X_train_transformed[y_train==1, 0], X_train_transformed[y_train==1, 1], 
           c='blue', label='Class 1', alpha=0.7)
plt.xlabel('First discriminant')
plt.ylabel('Second discriminant')
plt.title('LDA Projection (Training Set)')
plt.legend()

plt.subplot(122)
plt.scatter(X_test_transformed[y_test==0, 0], X_test_transformed[y_test==0, 1], 
           c='red', label='Class 0', alpha=0.7)
plt.scatter(X_test_transformed[y_test==1, 0], X_test_transformed[y_test==1, 1], 
           c='blue', label='Class 1', alpha=0.7)
plt.xlabel('First discriminant')
plt.ylabel('Second discriminant')
plt.title('LDA Projection (Test Set)')
plt.legend()
plt.tight_layout()
plt.show()

# 2. 打印解释方差比
print("\n解释方差比:")
for i, ratio in enumerate(lda.explained_variance_ratio_):
    print(f"判别式 {i+1}: {ratio:.4f}")

# 3. 绘制第一判别式的分布
plt.figure(figsize=(10, 6))
for label in [0, 1]:
    plt.hist(X_train_transformed[y_train==label, 0], 
             bins=30, alpha=0.5, 
             label=f'Class {label}')
plt.xlabel('First Discriminant')
plt.ylabel('Frequency')
plt.title('Distribution of First Discriminant')
plt.legend()
plt.show()

# 4. 进行预测和评估
y_pred = lda.predict(X_test)

# 5. 绘制混淆矩阵
plt.figure(figsize=(8, 6))
cm = confusion_matrix(y_test, y_pred)
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues')
plt.title('Confusion Matrix')
plt.xlabel('Predicted')
plt.ylabel('True')
plt.show()

# 6. 打印分类报告
print("\n分类报告:")
print(classification_report(y_test, y_pred))

# 7. 计算并显示类间距离
class_0_mean = X_train_transformed[y_train==0].mean(axis=0)
class_1_mean = X_train_transformed[y_train==1].mean(axis=0)
distance = np.linalg.norm(class_0_mean - class_1_mean)
print(f"\n类间欧氏距离: {distance:.4f}")

# 8. 计算每个特征的判别能力
feature_importance = np.abs(lda.w)
plt.figure(figsize=(10, 6))
plt.bar(range(lda.w.shape[0]), feature_importance[:, 0])
plt.title('Feature Importance (First Discriminant)')
plt.xlabel('Feature Index')
plt.ylabel('Absolute Weight')
plt.show()

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4.3 结果分析

4.3.1 判别式分布分析

从图"Distribution of First Discriminant"可以观察到:

  1. 两个类别在第一判别式上有明显的分离
  2. Class 0(蓝色)主要分布在负值区域,峰值在-0.05附近
  3. Class 1(红色)主要分布在正值区域,峰值在0.1附近
  4. 两类存在一定重叠区域,说明分类不是完全线性可分的

4.3.2 投影效果分析

从LDA投影散点图(训练集和测试集)可以看出:

  1. 训练集和测试集表现出相似的分布模式,说明模型具有良好的泛化能力
  2. 第一判别式(x轴)提供了主要的分类信息,这与解释方差比(2.3878)相对应
  3. 第二判别式(y轴)提供了补充信息,但贡献较小(解释方差比0.2540)
  4. 两个类别呈现出明显的对角线分布趋势,说明两个判别式都对分类有贡献

4.3.3 混淆矩阵分析

混淆矩阵显示:

  • 真正例(TP):133个样本
  • 真负例(TN):101个样本
  • 假正例(FP):29个样本
  • 假负例(FN):37个样本

模型性能指标:

  • 准确率 = (133 + 101)/(133 + 101 + 29 + 37) = 77.67%
  • 精确率 = 133/(133 + 29) = 82.10%
  • 召回率 = 133/(133 + 37) = 78.24%
  • F1分数 = 2 * (精确率 * 召回率)/(精确率 + 召回率) = 80.12%

4.3.4 总体评估

  1. 模型表现:

    • 整体分类效果良好,准确率达到77.67%
    • 两个类别的分类性能相对平衡
    • 第一判别式贡献了大部分分类信息(约90.4%)
  2. 优势:

    • 数据降维效果明显
    • 类别分离度好
    • 训练集和测试集表现一致
  3. 局限性:

    • 存在一定的分类错误
    • 类别重叠区域可能需要非线性方法进一步优化
  4. 改进建议:

    • 考虑增加特征工程
    • 尝试非线性核LDA
    • 结合其他分类器形成集成模型

5. LDA与PCA的比较

5.1 相同点

  • 都是常用的降维方法
  • 都是线性降维方法
  • 都可以用于特征提取

5.2 不同点

  1. 监督与否:

    • LDA是监督学习方法,需要标签信息
    • PCA是非监督学习方法,不需要标签信息
  2. 优化目标:

    • LDA最大化类间方差,最小化类内方差
    • PCA最大化投影方差
  3. 应用场景:

    • LDA更适合分类问题
    • PCA更适合数据压缩和可视化

6. LDA的优缺点

6.1 优点

  1. 可以用于降维和分类
  2. 计算简单,易于实现
  3. 对数据分布有较好的解释性
  4. 在小样本情况下表现良好

6.2 缺点

  1. 假设数据服从高斯分布
  2. 对非线性问题效果不好
  3. 类内散度矩阵可能奇异
  4. 降维维数受限于类别数-1

7. 实际应用场景

  1. 人脸识别
  2. 文本分类
  3. 医学诊断
  4. 语音识别
  5. 生物特征识别

8. 总结

LDA是一种经典且实用的算法,特别适合处理有监督的降维问题。虽然有一些限制,但在实际应用中仍然是一个很好的选择,尤其是在需要降维且数据大致符合高斯分布的场景下。

9. 参考文献

  1. Fisher, R. A. (1936). The use of multiple measurements in taxonomic problems
  2. Duda, R. O., Hart, P. E., & Stork, D. G. (2012). Pattern classification
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值