在sklearn.decomposition.PCA中,为什么组件是负的?

2024-04-23 08:19:31 发布

您现在位置:Python中文网/ 问答频道 /正文

我试图遵循Abdi&Williams-Principal Component Analysis(2010),并使用^{}通过SVD构建主组件。

当我使用sklearn显示拟合PCA中的^{}属性时,它们的大小与我手动计算的大小完全相同,但是有些(不是所有)是相反的符号。这是什么原因?

更新:下面的我的(部分)回答包含一些附加信息。

以以下数据为例:

from pandas_datareader.data import DataReader as dr
import numpy as np
from sklearn.decomposition import PCA
from sklearn.preprocessing import scale

# sample data - shape (20, 3), each column standardized to N~(0,1)
rates = scale(dr(['DGS5', 'DGS10', 'DGS30'], 'fred', 
           start='2017-01-01', end='2017-02-01').pct_change().dropna())

# with sklearn PCA:
pca = PCA().fit(rates)
print(pca.components_)
[[-0.58365629 -0.58614003 -0.56194768]
 [-0.43328092 -0.36048659  0.82602486]
 [-0.68674084  0.72559581 -0.04356302]]

# compare to the manual method via SVD:
u, s, Vh = np.linalg.svd(np.asmatrix(rates), full_matrices=False)
print(Vh)
[[ 0.58365629  0.58614003  0.56194768]
 [ 0.43328092  0.36048659 -0.82602486]
 [-0.68674084  0.72559581 -0.04356302]]

# odd: some, but not all signs reversed
print(np.isclose(Vh, -1 * pca.components_))
[[ True  True  True]
 [ True  True  True]
 [False False False]]

Tags: fromimportfalsetruedataasnpsklearn
3条回答

对于三维的主成分分析,你基本上可以迭代地找到:1)保留最大方差的一维投影轴2)垂直于1的最大方差保留轴。第三个轴自动与前两个轴垂直。

根据解释的方差列出成分。所以第一个解释了最大的方差,以此类推。注意,根据PCA操作的定义,当您试图在第一步中找到用于投影的向量(这将保留的方差最大化)时,向量的符号无关紧要:让M作为您的数据矩阵(在您的情况下,形状为(20,3))。假设v1是在投影数据时保持最大方差的向量。当选择-v1而不是v1时,将获得相同的方差。(你可以看看这个)。然后,当选择第二个向量时,让v2是垂直于v1并保留最大方差的向量。同样,选择-v2而不是v2将保持相同的方差。然后可以选择v3作为-v3或v3。这里,唯一重要的是v1,v2,v3构成数据M的正交基。符号主要取决于算法如何解决PCA操作背后的特征向量问题。特征值分解或奇异值分解在符号上可能不同。

经过一番挖掘,我澄清了一些,但不是全部,我在这方面的困惑。此问题已在stats.stackexchangehere中讨论过。数学上的答案是“PCA是一个简单的数学变换。如果更改组件的符号,则不会更改第一个组件中包含的方差。“但是,在这种情况下(使用sklearn.PCA),歧义的来源更为具体:在PCA的源(line 391)中,您有:

U, S, V = linalg.svd(X, full_matrices=False)
# flip eigenvectors' sign to enforce deterministic output
U, V = svd_flip(U, V)

components_ = V

svd_flip依次定义为here。但是,为什么这些标志会被翻转成“确保输出deterministic”,我不确定。(此时已找到U,S,V)。因此,虽然sklearn的实现并不错误,但我认为这并不是那么直观。任何熟悉贝塔系数(beta)概念的金融界人士都会知道,第一主成分很可能与广义市场指数类似。问题是,sklearn实现会给第一个主组件带来很强的负加载。

我的解决方案是一个简化的version,它不实现svd_flip。它没有sklearn参数,比如svd_solver,但是有很多专门针对这个目的的方法,这是非常简单的。

正如你在回答中所发现的,奇异值分解(SVD)的结果在奇异向量方面并不唯一。实际上,如果X的SVD是sum^r\s^u i u i v^u i^top: enter image description here

当s_i以递减的方式排列时,你可以看到你可以改变u_1和v_1的符号(即“翻转”),负号将被取消,所以公式仍然成立。

这表明SVD是唯一的,直到左右奇异向量的符号对发生变化。

由于PCA只是X的SVD(或X^ top X的特征值分解),因此不能保证每次执行PCA时,它不会在同一X上返回不同的结果。可以理解,scikit learn实现希望避免这种情况:它们通过强制(任意的)绝对值中U嫒i的最大系数为正,保证返回的左右奇异向量(存储在U和V中)总是相同的。

如您所见阅读the source:首先他们用linalg.svd()计算U和V。然后,对于每个向量uòi(即u的行),如果其绝对值中的最大元素为正,则它们不会执行任何操作。否则,它们会将u-i改为-u-i,并将相应的左奇异向量v-i改为-v-i。如前所述,这不会改变SVD公式,因为减号取消。但是,现在可以保证在这个处理之后返回的U和V始终是相同的,因为符号上的不确定性已被删除。

相关问题 更多 >