如何通过SVD实现基于NumPy的核主成分分析(Kernel PCA)?
既然标准PCA中对输入矩阵的SVD、协方差矩阵($\frac{1}{n-1}(X-\mu)(X-\mu)T$)或Gram矩阵($XT X$)的特征值分解能得到等价结果,核PCA也可以通过对核矩阵K做SVD来实现,以下是具体步骤和代码:
核心逻辑
核矩阵K对应高维特征空间的Gram矩阵$\Phi(X)^T\Phi(X)$($\Phi$是核函数对应的特征映射)。由于K是对称半正定矩阵,它的SVD分解和特征值分解存在直接对应关系:SVD得到的奇异值是特征值的平方根,左奇异向量就是特征向量,且SVD的数值稳定性比特征值分解更好,还能避免出现微小负特征值的数值问题。
实现步骤与代码
1. (可选但关键)中心化核矩阵
和标准PCA需要中心化数据一样,核PCA通常需要先中心化核矩阵,对应高维空间中特征的零均值处理,公式为:
$$K_{centered} = K - \frac{1}{n}1_n K - \frac{1}{n}K 1_n + \frac{1}{n^2}1_n K 1_n$$
其中$n$是样本数,$1_n$是n×n的全1矩阵。用NumPy实现:
import numpy as np # 假设K是已有的n×n核矩阵 n = K.shape[0] ones_matrix = np.ones((n, n)) / n K_centered = K - ones_matrix @ K - K @ ones_matrix + ones_matrix @ K @ ones_matrix
如果你的K已经是中心化后的核矩阵(比如使用中心化核函数生成),可以跳过这一步。
2. 对中心化后的核矩阵做SVD分解
使用numpy.linalg.svd进行分解:
# full_matrices=False表示只返回非零奇异值对应的矩阵,节省内存 U, S, Vh = np.linalg.svd(K_centered, full_matrices=False)
这里:
U是左奇异向量矩阵,每一列对应K的特征向量(已归一化到L2范数为1)S是按降序排列的奇异值数组,每个奇异值$S_i = \sqrt{\lambda_i}$($\lambda_i$是K的特征值)Vh是右奇异向量的转置,由于K对称,Vh和U是等价的
3. 生成核PCA的投影矩阵
核PCA中,用于投影的归一化特征向量需要满足再生核希尔伯特空间中的单位长度,对应公式为$\frac{U[:,i]}{S[i]}$(因为$K \cdot U[:,i] = \lambda_i U[:,i] = S_i^2 U[:,i]$,除以$S_i$后满足空间内积的单位长度要求)。
如果要提取前k个主成分,代码如下:
k = 2 # 示例:取前2个主成分 # 生成投影矩阵 proj_matrix = U[:, :k] / S[:k] # 对样本进行投影,结果就是高维特征空间的主成分投影 projections = K_centered @ proj_matrix
和特征值分解实现的对应关系
对比你提供的特征值分解代码:
- SVD得到的
S就是代码中对特征值开平方后的结果,且已经按降序排列,无需额外排序 U的列对应代码中的eVecs.T,直接除以S的对应元素,就得到了代码中vec/val的归一化向量- SVD不会出现特征值分解中偶尔出现的微小负特征值,结果更稳定
内容的提问来源于stack exchange,提问作者arod

