局部保留投影(Locality Preserving Projections, LPP)是一种用于数据降维
的技术,尤其适用于非线性数据集
。
LPP的基本思想是在降维过程中尽可能地保持数据点之间的局部结构不变
,即在高维空间中相邻的数据点,在降维后的低维空间中也应该保持相邻。
假设在高维空间中,数据 X 和 Y 存在相邻关系,在降维后的空间中 X‘ 和 Y’ 关系与原高维空间相同
目标函数
LPP的目标函数是寻找一个投影矩阵
P
P
P,将高维数据
X
X
X 投影到低维空间
Y
Y
Y,使得在低维空间中,样本点之间的相对距离尽可能反映它们在高维空间中的局部邻域关系
。这通常通过最小化以下目标函数实现:
min
P
∑
i
=
1
N
∑
j
=
1
N
∣
∣
y
i
−
y
j
∣
∣
2
S
(
i
,
j
)
\min_P \sum_{i=1}^N \sum_{j=1}^N ||y_i - y_j||^2 S(i,j)
Pmini=1∑Nj=1∑N∣∣yi−yj∣∣2S(i,j)
公式解析
-
P
P
P:
投影矩阵
,我们希望求解的对象。 -
N
N
N:
数据集中样本的数量。
-
y
i
,
y
j
y_i, y_j
yi,yj:
投影后的样本点
,其中 Y = P X Y = PX Y=PX。 -
∣
∣
y
i
−
y
j
∣
∣
2
||y_i - y_j||^2
∣∣yi−yj∣∣2:
欧几里得距离的平方,表示两个投影点之间的距离。
-
S
(
i
,
j
)
S(i,j)
S(i,j):
相似度或权重矩阵
的元素,反映了样本 i i i和样本 j j j之间的相似度或邻近程度。如果 i i i和 j j j是邻居,则 S ( i , j ) S(i,j) S(i,j)较大;如果不是,则接近于0。
权重矩阵 S S S
权重矩阵
S
S
S的定义依赖于样本点之间的距离
。常见的定义方式有两种:
- 使用固定半径
ϵ
\epsilon
ϵ 的邻域:如果两个点之间的距离小于
ϵ
\epsilon
ϵ,则它们被认为是
邻居
,权重为 e − ∣ ∣ x i − x j ∣ ∣ 2 t e^{-\frac{||x_i-x_j||^2}{t}} e−t∣∣xi−xj∣∣2,否则权重为0。 - 使用
k
k
k-最近邻规则:对于每一个点
x
i
x_i
xi,找到距离它最近的
k
k
k 个点作为它的邻居,
然后计算相应的权重。
解决方法
求解
P
P
P 通常是通过求解广义特征值
问题实现的。具体而言,我们需要构造两个矩阵
M
M
M 和
E
E
E,其中
M
M
M 是相似度矩阵
S
S
S 的加权形式
,而
E
E
E 是一个单位矩阵减去
M
M
M 。最终的
P
P
P 是广义特征值问题
M
P
=
E
P
Λ
MP = EP\Lambda
MP=EPΛ 的特征向量构成的矩阵,其中
Λ
\Lambda
Λ是对角矩阵,包含对应的特征值。
LPP通过上述过程,能够在降维的同时,有效地保持数据的局部几何结构
,使其在模式识别、图像分析等领域有广泛的应用。
python代码
import numpy as np
from sklearn.datasets import fetch_lfw_people
from sklearn.decomposition import PCA
from sklearn.neighbors import kneighbors_graph
from scipy.linalg import eigh
import matplotlib.pyplot as plt
import matplotlib
matplotlib.use('TkAgg') # 或者尝试 'Agg'
# 加载数据
data = fetch_lfw_people(min_faces_per_person=70, resize=0.4)
X = data.data
num_data, num_features = X.shape
# 构建k-最近邻图
connectivity = kneighbors_graph(X, n_neighbors=5, include_self=True)
# 计算拉普拉斯矩阵
laplacian = 0.5 * (connectivity + connectivity.T).toarray()
degree = np.diag(np.sum(laplacian, axis=1))
laplacian = degree - laplacian
# 应用LPP
eigenvalues, eigenvectors = eigh(laplacian, b=degree)
projection_matrix = eigenvectors[:, :2]
# 可视化
plt.figure(figsize=(12, 6))
plt.subplot(1, 2, 1)
plt.scatter(X[:, 0], X[:, 1], c=data.target, cmap='rainbow')
plt.title('Original Data')
plt.subplot(1, 2, 2)
plt.scatter(projection_matrix[:, 0], projection_matrix[:, 1], c=data.target, cmap='rainbow')
plt.title('LPP Reduced Data')
plt.show()