全部版块 我的主页
论坛 数据科学与人工智能 人工智能 机器学习
62 0
2025-11-27

1. LDA算法原理

核心思想概述

线性判别分析(LDA)是一种有监督的特征降维技术,其主要目标是寻找一个最优的投影方向,使得在该方向上不同类别之间的分离度最大化,同时同一类别内部样本的聚集度也最大化。换句话说,LDA致力于实现类间差异最大化、类内差异最小化。

数学模型构建

为了量化上述目标,LDA引入了两个关键矩阵:类内散度矩阵和类间散度矩阵。

类内散度矩阵用于衡量每个类别内部样本的分布情况:

\[ S_w = \sum_{i=1}^c \sum_{x \in X_i} (x - \mu_i)(x - \mu_i)^T \]

类间散度矩阵则反映各个类别均值相对于整体均值的偏离程度:

\[ S_b = \sum_{i=1}^c n_i(\mu_i - \mu)(\mu_i - \mu)^T \]

其中,\( c \) 表示类别总数,\( X_i \) 是第 \( i \) 类的样本集合,\( \mu_i \) 为该类的均值向量,\( \mu \) 为所有样本的总体均值,\( n_i \) 是第 \( i \) 类的样本数量。

基于这两个矩阵,LDA定义了一个优化目标函数:

\[ J(W) = \frac{W^T S_b W}{W^T S_w W} \]

该函数旨在通过求解广义特征值问题,找到一组最优投影向量 \( W \),使投影后的数据具有最佳可分性。

2. MATLAB中的实现方法

标准LDA实现

以下为基本LDA算法的MATLAB代码实现:
function [W, projected_data] = lda(X, y, k)
% LDA线性判别分析
% 输入:
%   X: 数据矩阵 (n×d),n个样本,d个特征
%   y: 标签向量 (n×1)
%   k: 目标维度
% 输出:
%   W: 投影矩阵 (d×k)
%   projected_data: 降维后的数据 (n×k)

[n, d] = size(X);
classes = unique(y);
c = length(classes);

% 计算总体均值
total_mean = mean(X);

% 初始化散度矩阵
S_w = zeros(d, d);
S_b = zeros(d, d);

% 遍历每一类计算类内与类间散度
for i = 1:c
    class_idx = (y == classes(i));
    X_class = X(class_idx, :);
    n_i = sum(class_idx);

    % 类内散度
    class_mean = mean(X_class);
    class_cov = (X_class - class_mean)' * (X_class - class_mean);
    S_w = S_w + class_cov;

    % 类间散度
    mean_diff = (class_mean - total_mean)';
    S_b = S_b + n_i * (mean_diff * mean_diff');
end

% 求解广义特征值问题:S_b * W = λ * S_w * W
[eigen_vectors, eigen_values] = eig(S_b, S_w);

% 按特征值降序排列
[~, sort_idx] = sort(diag(eigen_values), 'descend');
eigen_vectors_sorted = eigen_vectors(:, sort_idx);

% 选取前k个最大特征值对应的特征向量
W = eigen_vectors_sorted(:, 1:min(k, c-1));

% 对原始数据进行投影变换
projected_data = X * W;
end

改进型LDA实现(应对奇异矩阵问题)

当类内散度矩阵 \( S_w \) 出现奇异或接近奇异时,直接求逆可能导致数值不稳定。为此,可在算法中加入正则化项以提升鲁棒性。
function [W, projected_data, explained] = lda_improved(X, y, k)
% 改进的LDA实现,解决S_w可能奇异的问题

[n, d] = size(X);
classes = unique(y);
c = length(classes);

% 确定最大可行降维维度
max_k = min(d, c-1);
if k > max_k
    k = max_k;
    warning('目标维度调整为 %d', k);
end

total_mean = mean(X);
S_w = zeros(d, d);
S_b = zeros(d, d);

% 构建类内与类间散度矩阵
for i = 1:c
    class_idx = (y == classes(i));
    X_class = X(class_idx, :);
    n_i = sum(class_idx);

    % 使用无偏协方差估计
    class_mean = mean(X_class);
    class_cov = cov(X_class) * (n_i - 1);
    S_w = S_w + class_cov;

    % 更新类间散度
    mean_diff = (class_mean - total_mean)';
    S_b = S_b + n_i * (mean_diff * mean_diff');
end

% 添加微小正则化项防止矩阵奇异
regularization = 1e-6 * eye(d);
S_w = S_w + regularization;

% 利用SVD提高数值稳定性
[U, S, V] = svd(S_w);

% 计算S_w^{-1/2}
sqrt_inv_Sw = V * diag(1./sqrt(diag(S))) * U';

% 转换问题为标准特征值分解
transformed_Sb = sqrt_inv_Sw * S_b * sqrt_inv_Sw;
[eigen_vectors_trans, eigen_values] = eig(transformed_Sb);

% 按特征值从大到小排序
[~, idx] = sort(diag(eigen_values), 'descend');
eigen_vectors_trans = eigen_vectors_trans(:, idx);

% 还原原始空间中的投影方向
W_normalized = sqrt_inv_Sw * eigen_vectors_trans;

% 取前k维作为最终投影矩阵
W = W_normalized(:, 1:k);

% 投影数据
projected_data = X * W;

% 输出解释能力(可选)
explained = diag(eigen_values(idx(1:k)));
explained = explained / sum(explained) * 100;
end

min(特征数, 类别数-1)

[此处为图片2]

% 转换为标准特征值问题
S_b_transformed = S_inv_sqrt' * S_b * S_inv_sqrt;
[eigen_vectors, eigen_values] = eig(S_b_transformed);

% 对特征值进行降序排列
[eigen_values_sorted, sort_idx] = sort(diag(eigen_values), 'descend');
eigen_vectors_sorted = eigen_vectors(:, sort_idx);

% 提取前k个特征向量
W_transformed = eigen_vectors_sorted(:, 1:k);

% 将变换后的投影矩阵映射回原始空间
W = S_inv_sqrt * W_transformed;

% 执行数据投影
projected_data = X * W;

% 计算各分量的方差解释率
explained = eigen_values_sorted(1:k) / sum(eigen_values_sorted) * 100;
end

3. 可视化示例

function demo_lda() % 演示LDA的实际应用效果 rng(42); % 设定随机种子以确保结果可复现 n_per_class = 50; % 生成三类四维高斯分布数据 X1 = mvnrnd([2, 2, 1, 1], eye(4), n_per_class); X2 = mvnrnd([-1, -1, 2, 2], eye(4), n_per_class); X3 = mvnrnd([0, 3, -1, 0], eye(4), n_per_class); % 合并数据与标签 X = [X1; X2; X3]; y = [ones(n_per_class, 1); 2*ones(n_per_class, 1); 3*ones(n_per_class, 1)]; % 使用改进的LDA方法将数据降至2维 k = 2; [W, projected_data, explained] = lda_improved(X, y, k); % 创建图形窗口用于多子图展示 figure('Position', [100, 100, 1200, 400]); % 展示原始数据中前两个特征维度的分布情况 subplot(1, 3, 1); gscatter(X(:, 1), X(:, 2), y); title('原始数据(前两个维度)'); xlabel('特征1'); ylabel('特征2'); legend('类1', '类2', '类3');
min(特征数, 类别数-1)
% 显示LDA降维后的二维可视化结果 subplot(1, 3, 2); gscatter(projected_data(:, 1), projected_data(:, 2), y); title('LDA降维结果(2维)'); xlabel(sprintf('LDA分量1 (%.1f%%)', explained(1))); ylabel(sprintf('LDA分量2 (%.1f%%)', explained(2))); legend('类1', '类2', '类3'); [此处为图片2] % 展示投影矩阵W的结构(热力图形式) subplot(1, 3, 3); imagesc(W); colorbar; title('投影矩阵 W'); xlabel('LDA分量'); ylabel('原始特征'); [此处为图片3] % 输出实验相关统计信息 fprintf('数据信息:\n'); fprintf(' 样本数: %d\n', size(X, 1)); fprintf(' 原始维度: %d\n', size(X, 2)); fprintf(' 降维后维度: %d\n', k); fprintf(' 类别数: %d\n', length(unique(y))); fprintf('方差解释率:\n'); for i = 1:k fprintf(' 分量%d: %.2f%%\n', i, explained(i)); end end

4. LDA与PCA的对比分析

function compare_lda_pca() % 对比线性判别分析与主成分分析的降维性能差异 load fisheriris; % 加载鸢尾花数据集 X = meas; y = grp2idx(species); % 将类别转换为索引值 % 对输入数据进行标准化处理 X = zscore(X); % 应用LDA进行二维降维 k = 2; [W_lda, X_lda] = lda_improved(X, y, k); % 应用PCA进行相同维度的降维 [coeff, score, ~, ~, explained_pca] = pca(X); X_pca = score(:, 1:k); % 绘制对比图:左侧为LDA,右侧为PCA figure('Position', [100, 100, 1000, 400]); subplot(1, 2, 1);
function lda_classification_demo()
    % LDA在分类问题中的应用演示
    % 加载葡萄酒数据集
    [wine_data, wine_labels] = load_wine_data();
    
    if isempty(wine_data)
        fprintf('无法加载葡萄酒数据集,使用鸢尾花数据集代替\n');
        load fisheriris;
        X = meas;
        y = grp2idx(species);
        feature_names = {'SepalLength', 'SepalWidth', 'PetalLength', 'PetalWidth'};
    else
        X = wine_data;
        y = wine_labels;
        feature_names = {};
    end

    % 数据标准化处理
    X = zscore(X);

    % 划分训练集与测试集
    rng(123);
    cv = cvpartition(y, 'HoldOut', 0.3);
    X_train = X(cv.training, :);
    y_train = y(cv.training);
    X_test = X(cv.test, :);
    y_test = y(cv.test);

    % 方法一:基于原始特征直接分类
    fprintf('方法1: 直接使用原始特征\n');
    mdl_direct = fitcdiscr(X_train, y_train);
    y_pred_direct = predict(mdl_direct, X_test);
    accuracy_direct = sum(y_pred_direct == y_test) / length(y_test);

5. 实际应用案例

    % 应用PCA进行降维
    [X_pca, ~, explained_pca] = pca(X_train);
    X_test_pca = (X_test - mean(X_train)) * pca_basis; % 使用训练集的主成分方向变换测试集

    % 应用LDA进行降维
    [lda_model, X_train_lda] = fitcdiscr(X_train, y_train, 'DiscriminantType', 'linear');
    X_train_lda = X_train_lda(:, 1:end-1); % 取线性判别分量
    Mu = lda_model.Mu;
    W = cov(Mu); % 类均值的协方差作为类间散布估计
    V = lda_model.Sigma; % 模型协方差矩阵作为类内散布
    [eigvec, ~] = eig(W, V);
    X_train_lda = (X_train - lda_model.Mean) * eigvec(:, end-numClasses+2:end); % 投影到LDA空间
    X_test_lda = (X_test - lda_model.Mean) * eigvec(:, end-numClasses+2:end);

    % 方法二:结合LDA降维后的特征进行分类
    fprintf('方法2: 使用LDA降维后的特征\n');
    mdl_lda = fitcdiscr(X_train_lda, y_train);
    y_pred_lda = predict(mdl_lda, X_test_lda);
    accuracy_lda = sum(y_pred_lda == y_test) / length(y_test);

    % 方法三:使用PCA降维后分类
    fprintf('方法3: 使用PCA降维后的特征\n');
    mdl_pca = fitcdiscr(X_train_pca, y_train);
    y_pred_pca = predict(mdl_pca, X_test_pca);
    accuracy_pca = sum(y_pred_pca == y_test) / length(y_test);

    % 输出准确率对比
    fprintf('分类准确率比较:\n');
    fprintf('  原始特征: %.2f%%\n', accuracy_direct * 100);
    fprintf('  PCA降维后: %.2f%%\n', accuracy_pca * 100);
    fprintf('  LDA降维后: %.2f%%\n', accuracy_lda * 100);

    % 可视化降维结果(仅适用于前两个分量)
    figure;
    subplot(1, 2, 1);
    gscatter(X_pca(:, 1), X_pca(:, 2), y);
    title('PCA降维结果');
    xlabel(sprintf('PC1 (%.1f%%)', explained_pca(1)));
    ylabel(sprintf('PC2 (%.1f%%)', explained_pca(2)));
    legend('Setosa', 'Versicolor', 'Virginica');
    
min(特征数, 类别数-1)
subplot(1, 2, 2); gscatter(X_lda(:, 1), X_lda(:, 2), y); title('LDA降维结果'); xlabel('LDA分量1'); ylabel('LDA分量2'); legend('Setosa', 'Versicolor', 'Virginica'); [此处为图片2] % 性能评估:计算类间与类内距离比率 fprintf('分类性能评估:\n'); % 计算LDA投影空间中的类间/类内距离比 [~, lda_ratio] = calculate_separation_ratio(X_lda, y); fprintf('LDA 类间/类内距离比: %.4f\n', lda_ratio); % 计算PCA投影空间中的对应比率 [~, pca_ratio] = calculate_separation_ratio(X_pca, y); fprintf('PCA 类间/类内距离比: %.4f\n', pca_ratio); end function [separation_ratio, overall_ratio] = calculate_separation_ratio(X, y) % 计算类间距离与类内距离的比率以评估分离度 classes = unique(y); c = length(classes); % 计算总体中心 total_mean = mean(X); % 初始化类内散度 within_distance = 0; for i = 1:c class_idx = (y == classes(i)); X_class = X(class_idx, :); class_mean = mean(X_class); % 累加每一类的类内平方误差 within_distance = within_distance + sum(sum((X_class - class_mean).^2, 2)); end % 初始化类间散度 between_distance = 0; for i = 1:c class_idx = (y == classes(i)); n_i = sum(class_idx); class_mean = mean(X(class_idx, :)); % 累加加权的类间平方距离 between_distance = between_distance + n_i * sum((class_mean - total_mean).^2); end % 计算分离比 separation_ratio = between_distance / within_distance; overall_ratio = separation_ratio; end
% 方法2: 基于LDA降维的分类处理
k = min(2, length(unique(y_train)) - 1);
[W_lda, X_train_lda] = lda_improved(X_train, y_train, k);
X_test_lda = X_test * W_lda;
mdl_lda = fitcdiscr(X_train_lda, y_train);
y_pred_lda = predict(mdl_lda, X_test_lda);
accuracy_lda = sum(y_pred_lda == y_test) / length(y_test);
fprintf('LDA降维后分类准确率: %.2f%%\n', accuracy_lda * 100);

% 输出原始特征空间下的分类准确率
fprintf('直接分类准确率: %.2f%%\n', accuracy_direct * 100);

% 决策边界可视化(当降维至二维时)
if k == 2
    figure('Position', [100, 100, 800, 400]);
    subplot(1, 2, 1);
    plot_decision_boundary(X_train, y_train, mdl_direct, '原始特征决策边界');
    subplot(1, 2, 2);
    plot_decision_boundary_lda(X_train_lda, y_train, mdl_lda, 'LDA特征决策边界');
end
end

function plot_decision_boundary_lda(X, y, model, title_str)
    % 实现LDA空间中的决策边界绘制
    h = 0.02;
    x1_min = min(X(:, 1)) - 1; x1_max = max(X(:, 1)) + 1;
    x2_min = min(X(:, 2)) - 1; x2_max = max(X(:, 2)) + 1;
    [xx1, xx2] = meshgrid(x1_min:h:x1_max, x2_min:h:x2_max);
    Z = predict(model, [xx1(:), xx2(:)]);
    Z = reshape(Z, size(xx1));
    contourf(xx1, xx2, Z, 'Alpha', 0.3);
    hold on;
    gscatter(X(:, 1), X(:, 2), y);
    title(title_str);
    xlabel('LDA分量1');
    ylabel('LDA分量2');
    hold off;
min(特征数, 类别数-1)

6. LDA算法核心特性总结

特性 描述
监督学习 依赖类别标签进行投影方向优化
最大降维数 不超过类别数量减一
优化目标 最大化类间散度,同时最小化类内散度
典型应用场景 适用于分类任务与判别性特征提取
主要优势 利用类别信息提升分类可分性
局限性 对数据分布敏感,小样本下可能不稳定

使用建议与实践技巧

  • 数据预处理:推荐在执行LDA前对数据进行标准化,以消除量纲影响。
  • 维度选择原则:降维后的维度不应超过类别总数减去1。
  • 奇异矩阵应对策略:引入正则化项(如添加小量单位矩阵)以增强协方差矩阵的可逆性。
  • 结合PCA使用:对于高维且样本较少的情况,可先通过PCA去除冗余维度,再应用LDA进行判别分析,提高稳定性与效果。
二维码

扫码加我 拉你入群

请注明:姓名-公司-职位

以便审核进群资格,未注明则拒绝

栏目导航
热门文章
推荐文章

说点什么

分享

扫码加好友,拉您进群
各岗位、行业、专业交流群