为什么自行实现的PCA与sklearn库的PCA计算结果不一致
问题根本原因
你自行实现的PCA逻辑没有错误,二者输出仅存在符号差异,绝对值完全匹配,这是特征向量的固有性质导致的正常现象,不会影响PCA的后续使用效果。
- 特征向量的符号不唯一:从线性代数定义来看,某一特征值对应的特征向量乘以任意非零常数后,仍然是该特征值的有效特征向量,最常见的就是整体取反(乘-1),二者在方差解释能力上完全等价。
- 实现逻辑的差异:
- 你的实现使用
np.linalg.eig直接对协方差矩阵做特征分解,numpy返回的特征向量没有固定的符号约束,计算出来的符号和sklearn规则不一致。 - sklearn的PCA底层默认使用奇异值分解(SVD)实现,而非直接计算协方差矩阵的特征值,并且为了保证输出结果的可复现性,会强制让每个主成分分量中绝对值最大的元素符号为正,因此和你的实现出现了符号相反的情况。
- 你的实现使用
- 输出中那些接近0的极小值是浮点数计算的精度误差,属于正常情况,可以忽略。
如果你需要让你的实现和sklearn输出完全对齐,可以按如下规则调整特征向量的符号:
def my_pca(data, dim): remove_mean = data - data.mean(axis=0) cov_data = np.cov(remove_mean, rowvar=0) eig_val, eig_vec = np.linalg.eig(np.mat(cov_data)) sorted_eig_val = np.argsort(eig_val) eig_index = sorted_eig_val[:-(dim+1):-1] transfer = eig_vec[:,eig_index] # 新增:对齐sklearn的符号约束,每个主分量最大绝对值元素为正 for i in range(transfer.shape[1]): max_abs_idx = np.argmax(np.abs(transfer[:, i])) if transfer[max_abs_idx, i] < 0: transfer[:, i] *= -1 low_dim = remove_mean * transfer return np.array(low_dim, dtype=float)
调整后你的输出就会和sklearn完全一致。
内容的提问来源于stack exchange,提问作者jack
相关产品推荐
相关产品推荐

