目录
Python实现局部线性嵌入(LLE) 降维算法的博客
引言
随着数据维度的增加,高维数据的分析和处理变得更加复杂。为了简化数据的表示并提取有用的特征,降维技术被广泛应用。局部线性嵌入(Locally Linear Embedding, LLE)是流形学习中的一种经典降维算法。LLE通过保持数据的局部邻域结构,将高维数据嵌入到低维空间,特别适用于非线性降维问题。本文将详细介绍LLE算法的原理,并通过Python实现该算法,展示如何在实际场景中应用LLE进行数据降维。
LLE算法原理
局部线性嵌入的核心思想是利用每个数据点的局部邻域来保持数据的全局结构。LLE假设在高维空间中,数据点可以由其邻域中的点的线性组合表示。在降维过程中,LLE保持这些线性组合系数不变,从而将数据嵌入到低维空间。
1. 确定邻域
对于每一个数据点 x i x_i xi,LLE算法会找到它的 k k k个最近邻居。这个邻域反映了数据点局部的结构特性。
2. 线性重构
在找到邻域之后,LLE通过最小化重构误差来确定每个数据点在邻域内的线性组合系数。这些系数 w i j w_{ij} wij满足以下条件:
min ∑ i = 1 N ∥ x i − ∑ j = 1 k w i j x j ∥ 2 \min \sum_{i=1}^N \left\| x_i - \sum_{j=1}^k w_{ij}x_j \right\|^2 mini=1∑N xi−j=1∑kwijxj 2
其中 ∑ j = 1 k w i j = 1 \sum_{j=1}^k w_{ij} = 1 ∑j=1kwij=1,即权重系数的和为1。
3. 降维映射
在确定了线性组合系数 w i j w_{ij} wij 之后,LLE通过保持这些系数来实现降维映射。假设低维空间中的数据点为 y i y_i yi,则有:
min ∑ i = 1 N ∥ y i − ∑ j = 1 k w i j y j ∥ 2 \min \sum_{i=1}^N \left\| y_i - \sum_{j=1}^k w_{ij}y_j \right\|^2 mini=1∑N yi−j=1∑kwijyj 2
该优化问题的解可以通过求解一个特征值问题得到,从而实现从高维到低维的映射。
Python中的LLE实现
接下来我们将通过Python实现LLE算法,并将其封装到一个面向对象的类中,方便复用。
1. 创建LLE类
import numpy as np
from sklearn.neighbors import NearestNeighbors
class LLE:
def __init__(self, n_neighbors=5, n_components=2):
"""
初始化LLE类
:param n_neighbors: 每个数据点的邻居数量
:param n_components: 降维后的维度
"""
self.n_neighbors = n_neighbors
self.n_components = n_components
self.weights = None
self.embedding = None
def _compute_weights(self, X):
"""
计算线性重构的权重
:param X: 输入数据矩阵
:return: 权重矩阵
"""
nbrs = NearestNeighbors(n_neighbors=self.n_neighbors).fit(X)
_, indices = nbrs.kneighbors(X)
n_samples = X.shape[0]
weights = np.zeros((n_samples, self.n_neighbors))
for i in range(n_samples):
Z = X[indices[i]] - X[i] # 邻居中心化
C = np.dot(Z, Z.T) # 局部协方差矩阵
C += np.eye(self.n_neighbors) * 1e-3 # 增加对角线值以保证可逆性
w = np.linalg.solve(C, np.ones(self.n_neighbors))
weights[i, :] = w / np.sum(w) # 归一化权重
return weights
def fit_transform(self, X):
"""
对数据矩阵X进行LLE降维
:param X: 输入数据矩阵
:return: 降维后的数据矩阵
"""
self.weights = self._compute_weights(X)
n_samples = X.shape[0]
M = np.eye(n_samples)
for i in range(n_samples):
w = self.weights[i]
j = np.where(self.weights[i] != 0)[0]
M[i, j] -= w
M[j, i] -= w.T
M = np.dot(M.T, M)
_, eigvecs = np.linalg.eigh(M)
self.embedding = eigvecs[:, 1:self.n_components+1]
return self.embedding
2. 实现瑞士卷数据集的LLE降维
我们将在一个著名的非线性数据集——瑞士卷(Swiss Roll)数据集上应用LLE降维算法。瑞士卷数据集是一个三维数据集,形状类似于一块被卷起来的蛋糕。
from sklearn.datasets import make_swiss_roll
import matplotlib.pyplot as plt
# 生成瑞士卷数据集
X, color = make_swiss_roll(n_samples=1000, noise=0.2)
# 使用LLE进行降维
lle = LLE(n_neighbors=12, n_components=2)
X_r = lle.fit_transform(X)
# 绘制降维前后的数据分布
fig = plt.figure(figsize=(12, 6))
ax = fig.add_subplot(121, projection='3d')
ax.scatter(X[:, 0], X[:, 1], X[:, 2], c=color, cmap=plt.cm.Spectral)
ax.set_title("Original 3D data")
ax = fig.add_subplot(122)
ax.scatter(X_r[:, 0], X_r[:, 1], c=color, cmap=plt.cm.Spectral)
ax.set_title("2D embedding by LLE")
plt.show()
3. 结果分析
在上述实现中,我们首先对瑞士卷数据集进行了LLE降维,降维后的数据展示出了一条相对平滑的二维流形。这验证了LLE算法能够成功地将非线性高维数据映射到低维空间,同时保留数据的局部结构特性。
总结
局部线性嵌入(LLE)是一种有效的非线性降维方法,通过保持数据的局部邻域关系,将高维数据嵌入到低维空间。在本文中,我们详细介绍了LLE的数学原理,并通过Python实现了一个面向对象的LLE类。此外,我们还展示了如何在瑞士卷数据集上应用LLE进行降维,并取得了良好的效果。通过LLE算法,我们能够在保持数据局部结构的同时,显著降低数据的维度,从而为后续的机器学习任务打下基础。
这种方法不仅适用于瑞士卷数据集,还可以推广到其他具有非线性结构的数据集,如人脸图像、手写体数字等。希望这篇博客能够帮助你更好地理解LLE算法及其在实际应用中的潜力。
标签:neighbors,Python,self,降维,np,数据,LLE From: https://blog.csdn.net/qq_42568323/article/details/141571037