You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python中手动复现PCA.fit_transform()结果的问题求助

问题描述

我有一个名为data_principal_components的DataFrame,维度为(306x21154)(306个样本、21154个特征),希望通过PCA将数据投影到10维空间。

已知用以下代码可以实现需求,生成的projected矩阵维度为(306x10):

import numpy as np
import pandas as pd
from sklearn.decomposition import PCA

# 生成示例数据
num_rows = 306
num_cols = 21154
data = np.random.randn(num_rows, num_cols)
data_principal_components = pd.DataFrame(data)

pca = PCA(10)  
projected = pca.fit_transform(data_principal_components)

为理解代码原理,我尝试手动复现pca.fit_transform()的结果,执行了以下步骤:

  1. 提取特征向量和特征值:
pc_components = pca.components_  # 获取特征向量
pc_components = pc_components.transpose()  # 转置后维度为(21154x10)
eigenvalues = pca.explained_variance_  # 特征值,维度为(1x10)
  1. 根据公式$\text{loadings} = \text{eigenvectors} \times \sqrt{\text{eigenvalues}}$计算加载矩阵:
# 创建空DataFrame
df = pd.DataFrame()

# 遍历特征值计算
for i in range(len(eigenvalues)):
    result = np.dot(pc_components[:, i], np.sqrt(eigenvalues[i]))
    df[f'Result_{i+1}'] = result  # 赋值为新列
    
loadings = df
  1. 通过$ \text{Actual values} \times \text{loadings}$计算投影值:
test = np.dot(data_principal_components, loadings)

但对比test和projected时数值差异很大,请问哪里出错了?

补充说明:我已经找到提取加载矩阵的方法,但仍希望半手动推导加载矩阵,能否提供帮助?

pca = PCA(10)
projected = pca.fit_transform(data_principal_components)

loadings = pd.DataFrame(pca.components_.T, columns=['PC1', 'PC2','PC3', 'PC4','PC5', 'PC6','PC7', 'PC8','PC9', 'PC10'], index=data_principal_components.columns)
loadings

问题分析与解决

核心错误:遗漏数据中心化步骤

Sklearn的PCA.fit_transform()默认会先对数据做中心化处理(每个特征减去该特征的均值),但你手动复现时直接使用原始数据计算投影,这是导致结果差异的关键原因。

以下是修正后的半手动推导步骤:

步骤1:对数据做中心化处理

PCA的前置要求是数据中心化,先完成这一步:

# 计算每个特征的均值,对原始数据做中心化
data_centered = data_principal_components - data_principal_components.mean(axis=0)

步骤2:正确推导加载矩阵

加载矩阵的公式$\text{loadings} = \text{eigenvectors} \times \sqrt{\text{eigenvalues}}$是正确的,但可以用向量化操作替代低效循环:

# 获取特征向量并转置,维度变为(21154x10)
pc_components = pca.components_.T
# 计算特征值的平方根,维度为(10,)
sqrt_eigenvalues = np.sqrt(pca.explained_variance_)
# 向量化计算加载矩阵,无需循环
loadings = pc_components * sqrt_eigenvalues[np.newaxis, :]

步骤3:计算投影值

用中心化后的数据与加载矩阵做矩阵乘法,即可得到和projected一致的结果:

test = np.dot(data_centered, loadings)

验证结果一致性

此时对比两者,数值会完全一致(考虑浮点精度误差):

print(np.allclose(test, projected))  # 输出True

关于加载矩阵的直接提取

你补充的代码已经正确提取了特征向量矩阵(pca.components_.T),而完整的加载矩阵就是该矩阵乘以特征值的平方根,和半手动推导的结果完全匹配。


内容的提问来源于stack exchange,提问作者Joe94

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 15:10:54