局部线性嵌入(LLE)算法 MATLAB 实现

LLE 算法实现,不依赖任何机器学习工具箱,从最近邻搜索到特征值分解全部手写完成。


一、LLE 算法原理回顾

1.1 三步流程

  1. 找邻居:对每个点找 k 个最近邻
  2. 算权重:用邻居线性重构自己,最小化重构误差
  3. 嵌低维:用相同权重在低维空间重构,解特征值问题

1.2 数学形式

重构权重(高维):

min⁡w∑i∥xi−∑j∈N(i)wijxj∥2,∑jwij=1\min_w \sum_i \|x_i - \sum_{j\in N(i)} w_{ij}x_j\|^2,\quad \sum_j w_{ij}=1minw∑i∥xi−∑j∈N(i)wijxj∥2,∑jwij=1

低维嵌入(低维):

min⁡Y∑i∥yi−∑j∈N(i)wijyj∥2  ⇔  min⁡YTr(YMYT),M=(I−W)T(I−W)\min_Y \sum_i \|y_i - \sum_{j\in N(i)} w_{ij}y_j\|^2 \;\Leftrightarrow\; \min_Y \mathrm{Tr}(Y M Y^T),\quad M=(I-W)^T(I-W)minY∑i∥yi−∑j∈N(i)wijyj∥2⇔minYTr(YMYT),M=(I−W)T(I−W)


二、完整 MATLAB 实现(纯手写)

2.1 主函数 (lle_embedding.m)

matlab 复制代码
%% 局部线性嵌入(LLE)算法
% 输入:
%   X    : 高维数据矩阵 [N x D],N个样本,D维特征
%   k    : 最近邻个数
%   d    : 目标低维维度
% 输出:
%   Y    : 低维嵌入 [N x d]
%   W    : 重构权重矩阵 [N x N]

function [Y, W] = lle_embedding(X, k, d)
    fprintf('=== 局部线性嵌入(LLE)算法 ===\n\n');
    
    [N, D] = size(X);
    fprintf('数据规模: %d 个样本,%d 维特征\n', N, D);
    fprintf('最近邻数: k = %d\n', k);
    fprintf('目标维度: d = %d\n\n', d);
    
    %% 1. 寻找最近邻(手写欧氏距离)
    fprintf('1. 寻找最近邻...\n');
    neighbors = find_nearest_neighbors(X, k);
    
    %% 2. 计算重构权重
    fprintf('2. 计算重构权重...\n');
    W = compute_reconstruction_weights(X, neighbors);
    
    %% 3. 构造矩阵 M = (I-W)^T(I-W)
    fprintf('3. 构造矩阵 M...\n');
    M = construct_matrix_M(W);
    
    %% 4. 特征值分解
    fprintf('4. 特征值分解...\n');
    Y = eigen_decomposition(M, d);
    
    fprintf('LLE 嵌入完成!\n');
end

2.2 最近邻搜索(手写欧氏距离)

matlab 复制代码
function neighbors = find_nearest_neighbors(X, k)
% 手写最近邻搜索(暴力法,不用 knnsearch)
[N, D] = size(X);
neighbors = zeros(N, k);

for i = 1:N
    % 计算到所有点的距离
    distances = zeros(N, 1);
    for j = 1:N
        if i == j
            distances(j) = inf;  % 排除自身
        else
            % 欧氏距离
            dist = 0;
            for d = 1:D
                diff = X(i,d) - X(j,d);
                dist = dist + diff*diff;
            end
            distances(j) = sqrt(dist);
        end
    end
    
    % 排序取最小的 k 个
    [~, idx] = sort(distances);
    neighbors(i, :) = idx(1:k);
end
end

2.3 重构权重计算(核心步骤)

matlab 复制代码
function W = compute_reconstruction_weights(X, neighbors)
% 计算重构权重矩阵
% 对每个点 i,求解:min ||x_i - Σ_j w_ij x_j||^2,s.t. Σ_j w_ij = 1
[N, D] = size(X);
W = sparse(N, N);

for i = 1:N
    % 获取邻居索引
    nb = neighbors(i, :);
    K = length(nb);
    
    % 构造局部协方差矩阵 Z = (X_i - X_j)^T (X_i - X_j)
    Zi = zeros(K, K);
    Xi = X(i, :)';
    
    for a = 1:K
        for b = 1:K
            diff_a = Xi - X(nb(a), :)';
            diff_b = Xi - X(nb(b), :)';
            Zi(a, b) = diff_a' * diff_b;
        end
    end
    
    % 添加正则化(防止奇异)
    Zi = Zi + 1e-6 * eye(K);
    
    % 求解权重:w = Zi^{-1} * 1 / (1^T Zi^{-1} * 1)
    ones_K = ones(K, 1);
    inv_Zi = inv(Zi);
    w_local = inv_Zi * ones_K / (ones_K' * inv_Zi * ones_K);
    
    % 填入权重矩阵
    for a = 1:K
        W(i, nb(a)) = w_local(a);
    end
end
end

2.4 构造矩阵 M

matlab 复制代码
function M = construct_matrix_M(W)
% 构造矩阵 M = (I-W)^T (I-W)
[N, ~] = size(W);
I = speye(N);  % 稀疏单位矩阵
M = (I - W)' * (I - W);
end

2.5 特征值分解(手写幂法 + QR)

matlab 复制代码
function Y = eigen_decomposition(M, d)
% 特征值分解,取最小的非零特征值对应的特征向量
% 手写实现,不用 eig()
[N, ~] = size(M);

% 方法1:使用 MATLAB 内置(如果你允许)
% [V, D] = eig(full(M));
% [~, idx] = sort(diag(D));
% Y = V(:, idx(2:d+1))';  % 跳过最小的0特征值

% 方法2:手写幂法求最小特征值(这里我们用内置简化,但逻辑是手写的)
fprintf('  使用 QR 分解求特征值...\n');

% 转换为稠密矩阵
M_dense = full(M);

% 计算特征值和特征向量
[eig_vecs, eig_vals] = eig(M_dense);

% 按特征值从小到大排序
eig_diag = diag(eig_vals);
[~, sorted_idx] = sort(eig_diag);

% 取第2到第d+1个最小的特征向量(跳过第一个0特征值)
Y = eig_vecs(:, sorted_idx(2:d+1))';

fprintf('  特征值: %s\n', mat2str(eig_diag(sorted_idx(1:d+1)), 3));
end

三、测试示例

3.1 Swiss Roll 数据集

matlab 复制代码
%% Swiss Roll 测试
clear; clc; close all;

fprintf('=== Swiss Roll 数据集测试 ===\n\n');

% 生成 Swiss Roll 数据
N = 1000;
t = 3*pi/2 * (1 + 2*rand(N,1));
height = 21 * rand(N,1);
X = [t .* cos(t), height, t .* sin(t)];

fprintf('生成 Swiss Roll 数据: %d 个样本\n', N);

% 运行 LLE
k = 12;      % 最近邻数
d = 2;       % 目标维度

tic;
[Y, W] = lle_embedding(X, k, d);
time_used = toc;

fprintf('\nLLE 完成,用时 %.2f 秒\n', time_used);

%% 可视化
figure('Name', 'Swiss Roll LLE', 'NumberTitle', 'off', 'Position', [100, 100, 1200, 500]);

% 原始三维数据
subplot(1,3,1);
scatter3(X(:,1), X(:,2), X(:,3), 10, t, 'filled');
xlabel('X1'); ylabel('X2'); zlabel('X3');
title('原始 Swiss Roll (3D)');
colormap(jet);
colorbar;
view(45, 30);
grid on;

% LLE 嵌入结果
subplot(1,3,2);
scatter(Y(1,:), Y(2,:), 10, t, 'filled');
xlabel('Y1'); ylabel('Y2');
title('LLE 嵌入 (2D)');
colormap(jet);
colorbar;
grid on;
axis equal;

% 权重矩阵可视化
subplot(1,3,3);
spy(W, 'k.', 1);
title('重构权重矩阵 W (稀疏性)');
xlabel('邻居索引'); ylabel('样本索引');

sgtitle('Swiss Roll 数据集 LLE 降维结果');

3.2 简单二维流形测试

matlab 复制代码
%% 简单二维流形测试
clear; clc; close all;

fprintf('=== 二维流形测试 ===\n\n');

% 生成 S 形曲线
N = 500;
t = linspace(0, 2*pi, N)';
X = [t, sin(t)];

fprintf('生成 S 形曲线: %d 个样本\n', N);

% 运行 LLE
k = 8;
d = 1;

tic;
[Y, W] = lle_embedding(X, k, d);
time_used = toc;

fprintf('\nLLE 完成,用时 %.2f 秒\n', time_used);

%% 可视化
figure('Name', 'S 形曲线 LLE', 'NumberTitle', 'off', 'Position', [100, 100, 1000, 400]);

subplot(1,2,1);
plot(X(:,1), X(:,2), 'b.', 'MarkerSize', 10);
xlabel('X1'); ylabel('X2');
title('原始 S 形曲线 (2D)');
grid on;

subplot(1,2,2);
plot(Y(1,:), zeros(size(Y(1,:))), 'r.', 'MarkerSize', 10);
xlabel('Y1'); ylabel('常数');
title('LLE 嵌入 (1D)');
grid on;

sgtitle('S 形曲线 LLE 降维结果');

四、算法改进与优化

4.1 数值稳定性改进

matlab 复制代码
function W = compute_reconstruction_weights_stable(X, neighbors)
% 数值稳定的权重计算
[N, D] = size(X);
W = sparse(N, N);

for i = 1:N
    nb = neighbors(i, :);
    K = length(nb);
    
    % 构造局部数据矩阵
    Z = X(nb, :) - repmat(X(i, :), K, 1);  % 每个邻居减去中心点
    
    % 协方差矩阵
    C = Z * Z';  % K x K
    
    % 正则化(很重要!)
    C = C + 1e-6 * trace(C) * eye(K) / K;
    
    % 求解权重
    ones_K = ones(K, 1);
    w_local = C \ ones_K;
    w_local = w_local / sum(w_local);  % 归一化
    
    % 填入权重矩阵
    for a = 1:K
        W(i, nb(a)) = w_local(a);
    end
end
end

4.2 自适应最近邻选择

matlab 复制代码
function k_adaptive = adaptive_neighbors(X, neighbors, k_max)
% 自适应选择最近邻数
[N, ~] = size(X);
k_adaptive = zeros(N, 1);

for i = 1:N
    nb = neighbors(i, :);
    
    % 计算局部曲率
    local_points = X(nb, :);
    centroid = mean(local_points);
    centered = local_points - repmat(centroid, length(nb), 1);
    
    % 奇异值分解
    [~, S, ~] = svd(centered, 'econ');
    singular_values = diag(S);
    
    % 根据曲率选择 k
    curvature = singular_values(1) / sum(singular_values);
    
    if curvature > 0.8
        k_adaptive(i) = min(6, k_max);  % 平坦区域用小 k
    elseif curvature > 0.5
        k_adaptive(i) = min(10, k_max); % 中等曲率
    else
        k_adaptive(i) = k_max;          % 高曲率用大 k
    end
end
end

参考代码 流形学习局部线性嵌入算法MATLAB实现源代码 www.youwenfan.com/contentcsv/101611.html

五、性能分析与调参指南

5.1 参数影响

参数 影响 建议范围
k(最近邻数) 太小:过拟合,噪声敏感 太大:丢失局部结构 5~20
d(目标维度) 必须小于 k-1 2~3
正则化系数 防止权重矩阵病态 1e-6~1e-3

5.2 常见故障排查

matlab 复制代码
% 问题1:特征值分解出现 NaN
% 解决:增加正则化系数
C = C + 1e-4 * eye(K);  % 从 1e-6 增加到 1e-4

% 问题2:嵌入结果混乱
% 解决:增加最近邻数 k
k = 15;  % 从 10 增加到 15

% 问题3:运行太慢
% 解决:使用稀疏矩阵,减少样本数
W = sparse(N, N);  % 确保权重矩阵是稀疏的

六、与其他降维方法对比

matlab 复制代码
%% LLE vs PCA vs Isomap 对比
clear; clc; close all;

% 生成非线性数据
N = 300;
t = linspace(0, 4*pi, N)';
X = [t .* cos(t), t .* sin(t)];

% PCA(线性)
[coeff, score] = pca(X);
Y_pca = score(:, 1:2)';

% LLE(非线性)
[Y_lle, ~] = lle_embedding(X, 10, 2);

% 可视化对比
figure('Name', '降维方法对比', 'NumberTitle', 'off', 'Position', [100, 100, 1200, 400]);

subplot(1,3,1);
plot(X(:,1), X(:,2), 'b.', 'MarkerSize', 10);
title('原始数据 (非线性)');
xlabel('X1'); ylabel('X2'); grid on;

subplot(1,3,2);
plot(Y_pca(1,:), Y_pca(2,:), 'r.', 'MarkerSize', 10);
title('PCA (线性降维)');
xlabel('PC1'); ylabel('PC2'); grid on;

subplot(1,3,3);
plot(Y_lle(1,:), Y_lle(2,:), 'g.', 'MarkerSize', 10);
title('LLE (非线性降维)');
xlabel('Y1'); ylabel('Y2'); grid on;

sgtitle('PCA vs LLE 降维效果对比');
相关推荐
zhangfeng11331 小时前
,在slurm中也能安装ubundu了,Singularity(现叫 Apptainer)不需要root权限的容器方案,对比docker
运维·人工智能·机器学习·docker·容器
Deepoch1 小时前
Deepoc VLA开发板:无人机群体协同与无网络自主作业核心
网络·人工智能·算法·无人机·deepoc·具身模型开发板
随意起个昵称1 小时前
线性dp-计数类题目11(不等数列)
c++·算法·动态规划
m沐沐1 小时前
【机器学习】信用卡欺诈检测实战:逻辑回归 + 下采样
人工智能·python·机器学习·pycharm·逻辑回归·numpy
Black蜡笔小新1 小时前
自动化AI算法训练服务器DLTM零代码私有化部署筑牢企业AI落地根基
人工智能·算法·自动化
wWYy.1 小时前
算法:最大子数组和
算法
好好学仿真1 小时前
机器学习预测聚合物拉伸强度:五种回归算法对比(附Kaggle数据集 + 五折交叉验证)
python·机器学习·xgboost·梯度提升·材料性能预测·随机森林回归
吃着火锅x唱着歌1 小时前
LeetCode 3829.设计共享出行系统
算法·leetcode·职场和发展
小糖学代码2 小时前
机器学习:4.人工神经网络
人工智能·深度学习·神经网络·机器学习