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

如何缩放行坐标散点图与相关圆合并为Biplot?附Sklearn PCA疑问

中心化未缩放数据的PCA Biplot问题解决及Sklearn PCA说明

一、prince包Biplot缩放问题解决

你遇到的散点图比例失调,是因为prince返回的行主坐标(主成分得分)和变量相关系数尺度不匹配:

  • 行主坐标的方差等于对应主成分的特征值,尺度远大于相关系数的[-1,1]范围
  • 变量相关系数(column_correlations()返回值)是变量与主成分的线性相关程度,范围固定在[-1,1]

解决方法是对行主坐标进行缩放,使其尺度与相关系数匹配:

  1. 获取prince PCA模型的特征值(pca.eigenvalues_)
  2. 将每行的主成分得分除以对应特征值的平方根,让得分的方差变为1,和相关系数尺度对齐

示例代码:

import prince
import matplotlib.pyplot as plt
import pandas as pd

# 假设data是已中心化的数据集
pca = prince.PCA(n_components=2, rescale_with_mean=True, rescale_with_std=False)
pca.fit(data)

# 获取行主坐标并缩放
row_scores = pca.transform(data)
scaled_row_scores = row_scores / pca.eigenvalues_.values ** 0.5

# 获取变量与主成分的相关系数
var_corrs = pca.column_correlations()

# 绘制Biplot
fig, ax = plt.subplots(figsize=(8, 8))
# 绘制缩放后的行散点
ax.scatter(scaled_row_scores.iloc[:, 0], scaled_row_scores.iloc[:, 1], alpha=0.6)
# 绘制变量箭头与标签
for idx, row in var_corrs.iterrows():
    ax.arrow(0, 0, row[0], row[1], head_width=0.05, head_length=0.05, color='red')
    ax.text(row[0]+0.05, row[1]+0.05, idx, color='red')
# 添加相关圆
circle = plt.Circle((0, 0), 1, color='gray', fill=False)
ax.add_artist(circle)

ax.set_xlim(-1.5, 1.5)
ax.set_ylim(-1.5, 1.5)
ax.set_xlabel(f'PC1 ({pca.explained_inertia_[0]:.1%})')
ax.set_ylabel(f'PC2 ({pca.explained_inertia_[1]:.1%})')
ax.grid(True)
plt.show()

二、Sklearn PCA变量坐标错误的原因及解决方法

原因

Sklearn的PCA并没有计算错误,是你混淆了两个核心概念:

  • PCA.components_返回的是协方差矩阵的特征向量(载荷向量),这些向量是单位向量(L2范数为1),反映的是变量对主成分的协方差贡献,不是变量与主成分的相关系数
  • 相关圆需要的坐标是变量与主成分的线性相关系数,它需要结合特征值和变量标准差计算,公式为:
    r(Xj, PCk) = (components_[k,j] * sqrt(explained_variance_[k])) / std(Xj)
    
    其中explained_variance_[k]是第k个主成分的特征值,std(Xj)是第j个变量的原始标准差

直接用components_绘制相关圆,会把协方差关系当成相关关系,导致变量的相关性显示错误(比如负相关变量显示正交)。

解决方法

手动计算变量与主成分的相关系数作为坐标,再绘制相关圆:

from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler
import numpy as np
import matplotlib.pyplot as plt

# 中心化数据
scaler = StandardScaler(with_std=False)
data_centered = scaler.fit_transform(data)

# 训练Sklearn PCA
pca = PCA(n_components=2)
row_scores = pca.fit_transform(data_centered)

# 计算变量与主成分的相关系数坐标
var_stds = data.std(axis=0)
var_corrs = pca.components_.T * np.sqrt(pca.explained_variance_) / var_stds.values[:, np.newaxis]

# 绘制Biplot(行得分同样需要缩放以匹配相关系数尺度)
scaled_row_scores = row_scores / np.sqrt(pca.explained_variance_)

fig, ax = plt.subplots(figsize=(8, 8))
ax.scatter(scaled_row_scores[:, 0], scaled_row_scores[:, 1], alpha=0.6)
for i, (x, y) in enumerate(var_corrs):
    ax.arrow(0, 0, x, y, head_width=0.05, head_length=0.05, color='red')
    ax.text(x+0.05, y+0.05, data.columns[i], color='red')

circle = plt.Circle((0, 0), 1, color='gray', fill=False)
ax.add_artist(circle)
ax.set_xlim(-1.5, 1.5)
ax.set_ylim(-1.5, 1.5)
ax.set_xlabel(f'PC1 ({pca.explained_variance_ratio_[0]:.1%})')
ax.set_ylabel(f'PC2 ({pca.explained_variance_ratio_[1]:.1%})')
ax.grid(True)
plt.show()

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 21:18:37