高维数据PCA实现疑问:为何无法得到与标准PCA一致的特征向量?
解决高维数据PCA中特征向量不一致的问题
嗨,我明白你遇到的问题了——当处理高维数据(维度D远大于样本数N)时,我们确实会转向计算X @ X.T来避免处理大尺寸的协方差矩阵,但直接用X.T @ eig_vecs得到的向量和标准PCA的特征向量不一致,核心问题出在归一化步骤缺失,还有特征值的筛选和排序细节。
让我一步步拆解原因和解决方案:
原理回顾
首先明确一个关键结论:对于矩阵X(N×D),X.T @ X(D×D)和X @ X.T(N×N)的非零特征值完全相同,但特征向量存在转换关系:
如果
v是X @ X.T的特征向量(对应特征值λ≠0),那么u = X.T @ v是X.T @ X的特征向量(对应同一特征值λ)。
但这里有个容易忽略的点:u的模长并不是1,而标准PCA得到的特征向量都是单位向量,所以必须对u做归一化处理。
修正后的高维PCA流程
针对你的示例数据,我们可以这样修正代码:
import numpy as np X_normalized = np.array([[-0.41873524, 0.16431545, -0.56998025, -0.11733312], [-0.28466524, 0.30149955, 0.68094323, -0.35746243], [ 0.74718755, -1.46799525, -1.38690518, 0.29022802], [ 0.51785433, 0.2600977 , 2.48749719, 0.79531581], [-0.56164139, 0.74208255, -1.211555 , -0.61074828]]) N, D = X_normalized.shape # 高维PCA流程 S_N = np.dot(X_normalized, X_normalized.T) / N eig_vals_N, eig_vecs_N = np.linalg.eig(S_N) # 1. 过滤掉接近0的特征值(数值计算误差导致的微小值) non_zero_mask = eig_vals_N > 1e-8 filtered_eig_vals = eig_vals_N[non_zero_mask] filtered_eig_vecs = eig_vecs_N[:, non_zero_mask] # 2. 转换并归一化得到X.T@X的特征向量 high_dim_eig_vecs = [] for v in filtered_eig_vecs.T: u = np.dot(X_normalized.T, v) # 归一化到单位向量 u_normalized = u / np.linalg.norm(u) high_dim_eig_vecs.append(u_normalized) high_dim_eig_vecs = np.array(high_dim_eig_vecs).T # 标准PCA流程对比 S_D = np.dot(X_normalized.T, X_normalized) / N std_eig_vals, std_eig_vecs = np.linalg.eig(S_D) # 对两者的特征值排序,确保顺序一致(因为eig返回的顺序不一定是降序) # 排序索引:从大到小 std_sort_idx = np.argsort(std_eig_vals)[::-1] high_dim_sort_idx = np.argsort(filtered_eig_vals)[::-1] sorted_std_vecs = std_eig_vecs[:, std_sort_idx] sorted_high_dim_vecs = high_dim_eig_vecs[:, high_dim_sort_idx] # 检查结果:允许符号相反(特征向量方向不唯一) print("标准PCA特征向量(前2个):") print(sorted_std_vecs[:, :2]) print("\n高维PCA修正后特征向量(前2个):") print(sorted_high_dim_vecs[:, :2]) print("\n是否一致(考虑符号):") print(np.allclose(np.abs(sorted_std_vecs), np.abs(sorted_high_dim_vecs)))
关键细节说明
- 归一化:这是你之前遗漏的核心步骤。
X.T @ v的模长等于sqrt(λ)(λ是对应特征值),所以除以np.linalg.norm(u)才能得到单位特征向量。 - 特征值筛选:当N<D时,
X @ X.T最多有N个非零特征值,剩下的都是数值计算产生的极小值,需要过滤掉,避免引入无效的特征向量。 - 排序与符号:
np.linalg.eig返回的特征值/向量是无序的,所以需要按特征值降序排序后再对比。- 特征向量的符号可能和标准PCA结果相反,这是完全正常的——主成分的方向本身就不唯一(取反后依然能解释相同的方差),所以对比时可以用
np.allclose(np.abs(a), np.abs(b))来验证。
验证结果
运行上面的代码后,你会看到修正后的高维PCA特征向量和标准PCA的特征向量(除了可能的符号差异)完全一致,满足你的预期。
内容的提问来源于stack exchange,提问作者Jiriki
相关产品推荐
相关产品推荐

