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

使用Sklearn绘制的主成分存在角度偏移,求排查问题原因

问题与解决方法

问题描述

我生成了200,000个服从多元正态分布的样本数据,想用Sklearn的PCA查看捕获最大方差的主成分形态。对PCA得到的特征向量做归一化后,按特征值平方根缩放绘图,发现主成分未如预期平分数据分布,反而存在角度偏移,无法定位问题。

原代码

import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
from sklearn.decomposition import PCA

# generate synthetic data with a linear relationship
np.random.seed(0)
mean = [0, 0]  # mean of both features
cov = [[1, 0.8], [0.8, 1]]  # covariance matrix to sample from
data = np.random.multivariate_normal(mean, cov, 200000) # sample data points with given parameters

# feature cols
feature_1 = data[:, 0]
feature_2 = data[:, 1]

# perform PCA
pca = PCA(n_components=2)
principal_components = pca.fit_transform(data)

# principal component vectors
eigenvectors = pca.components_
eigenvalues = pca.explained_variance_
eigenvectors_unit = eigenvectors / np.linalg.norm(eigenvectors, axis=1, keepdims=True) # computing unit eigenvectors

pc1 = eigenvectors_unit[0, :] * np.sqrt(eigenvalues[0])
pc2 = eigenvectors_unit[1, :] * np.sqrt(eigenvalues[1])


# plot principal components
plt.figure(figsize=(8, 6))
sns.scatterplot(x=feature_1, y=feature_2, color='black', alpha=0.8)
plt.title('Principal Components')

origin = np.zeros(2)
plt.quiver(origin[0], origin[1], pc1[0], pc1[1], color='red', scale=5)
plt.quiver(origin[0], origin[1], pc2[0], pc2[1], color='blue', scale=5)
plt.tight_layout()
plt.show()

问题根源与修正

问题主要出在两个核心点:

  1. plt.quiver的scale参数:设置scale=5会强制缩放箭头长度,导致主成分向量的显示比例失真,视觉上出现角度偏移。
  2. 坐标轴比例不一致:默认绘图时x、y轴刻度间距可能不同,即使向量角度正确,视觉上也会显得偏移。
  3. 额外的归一化操作:Sklearn的PCA.components_返回的已经是单位特征向量,无需手动重复归一化(这步不影响结果,但属于冗余操作)。

修正后的代码

import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
from sklearn.decomposition import PCA

# 生成带线性关系的合成数据
np.random.seed(0)
mean = [0, 0]  # 两个特征的均值
cov = [[1, 0.8], [0.8, 1]]  # 采样用的协方差矩阵
data = np.random.multivariate_normal(mean, cov, 200000) # 生成指定参数的样本点

# 提取特征列
feature_1 = data[:, 0]
feature_2 = data[:, 1]

# 执行PCA
pca = PCA(n_components=2)
principal_components = pca.fit_transform(data)

# 主成分向量(已为单位向量)
eigenvectors = pca.components_
eigenvalues = pca.explained_variance_

# 按特征值平方根缩放,对应数据在该主成分上的标准差
pc1 = eigenvectors[0, :] * np.sqrt(eigenvalues[0])
pc2 = eigenvectors[1, :] * np.sqrt(eigenvalues[1])

# 绘图
plt.figure(figsize=(8, 6))
sns.scatterplot(x=feature_1, y=feature_2, color='black', alpha=0.8)
plt.title('主成分展示')

origin = np.zeros(2)
# 去掉scale参数,保留向量真实长度
plt.quiver(origin[0], origin[1], pc1[0], pc1[1], color='red')
plt.quiver(origin[0], origin[1], pc2[0], pc2[1], color='blue')
plt.axis('equal')  # 设置坐标轴等比例,避免视觉角度偏移
plt.tight_layout()
plt.show()

关键修正点说明

  • 移除plt.quiver的scale参数,让箭头长度完全匹配计算出的主成分向量长度(对应数据在该维度的标准差)。
  • 添加plt.axis('equal'):强制x、y轴使用相同的刻度间距,确保向量角度的视觉呈现与实际一致。
  • 移除冗余的归一化步骤,直接使用PCA.components_提供的单位特征向量。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 19:23:24