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

从零实现PCA:幂法求解特征值仅首个正确的问题排查求助

问题分析与修复方案

你的核心问题出在两个关键环节:幂法的向量归一化方式错误,以及矩阵消去逻辑依赖错误的特征向量,导致后续特征值计算完全偏离。

错误点1:幂法的归一化选择错误

你用max(v)作为归一化系数,这是错误的。幂法正确的做法是用向量的**L2范数(欧几里得范数)**来归一化,因为我们需要的是单位向量,而不是最大值为1的向量。用最大值归一化会破坏幂法收敛到主特征向量的逻辑,后续消去矩阵时误差会被指数级放大。

错误点2:矩阵消去(Deflation)的前提不成立

当你用错误的特征向量去更新协方差矩阵时,消去后的矩阵已经不再是原矩阵减去主特征子空间的投影,后续幂法计算的自然不是次大的特征值。

修正后的完整代码

import numpy as np
import pandas as pd
from sklearn.preprocessing import StandardScaler

def normalize_data(train_x, test_x=None):
    scaler = StandardScaler()
    train_normalized = pd.DataFrame(scaler.fit_transform(train_x), columns=train_x.columns)
    test_normalized = pd.DataFrame(scaler.transform(test_x), columns=test_x.columns) if test_x is not None else None
    return train_normalized, test_normalized

def extract_PCA(X, n_components=3):
    n = X.shape[0]
    cov_matrix = (X.T @ X) / (n-1)    
    eigen_vectors = []
    eigen_values = []
        
    for _ in range(n_components):
        # 计算当前矩阵的主特征值和特征向量
        eigen_value, eigen_vector = using_power_method_find_dominant_eigen_value(cov_matrix)
        eigen_values.append(eigen_value)
        eigen_vectors.append(eigen_vector)
        
        # 矩阵消去:减去当前特征值对应的投影矩阵
        eigen_vector = eigen_vector.reshape(-1, 1)
        cov_matrix = cov_matrix - eigen_value * eigen_vector @ eigen_vector.T
    
    print("计算得到的特征值:", eigen_values)
    return eigen_values, eigen_vectors

def using_power_method_find_dominant_eigen_value(mat_A, tolerance=1e-10, max_iter=1000):
    n = mat_A.shape[0]
    # 初始化随机向量(比全1向量更稳定)
    x = np.random.rand(n)
    x = x / np.linalg.norm(x)  # 初始化为单位向量
    
    prev_value = 0
    prev_eigen_vector = x.copy()

    for _ in range(max_iter):
        x = mat_A @ x
        norm = np.linalg.norm(x)
        eigen_value = norm
        x = x / norm  # L2范数归一化
        
        # 检查收敛条件
        if abs(eigen_value - prev_value) < tolerance and np.linalg.norm(prev_eigen_vector - x) < tolerance:
            break
            
        prev_value = eigen_value
        prev_eigen_vector = x.copy()
        
    return eigen_value, x

if __name__ == "__main__":
    train_df = pd.read_csv("train.csv")
    test_df = pd.read_csv("test.csv")
    
    X_train, y_train = train_df.drop(columns=['y'], axis=1), train_df['y']
    X_test, y_test = test_df.drop(columns=['y'], axis=1), test_df['y']
    
    X_train, X_test = normalize_data(X_train, X_test)
    extract_PCA(X_train)

关键修正说明

  • 替换原vector_norm函数的逻辑,直接用np.linalg.norm做L2归一化,保证特征向量是单位向量。
  • 初始化向量改为随机向量,避免全1向量在某些特殊矩阵下收敛缓慢。
  • 简化幂法的迭代逻辑,用numpy矩阵运算替代列表推导,提升效率和准确性。
  • 确保消去矩阵时使用的是单位特征向量,保证投影矩阵的正确性。

运行修正后的代码,计算得到的特征值会和numpy的结果一致:[9.49506917, 8.11919641, 5.27687829]。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 07:34:58