在sklearn.decomposition.PCA中,为什么components_为负?

时间:2017-06-26 17:53:17

标签: python python-3.x numpy scikit-learn pca

我试图跟随Abdi&威廉姆斯 - Principal Component Analysis(2010)并使用numpy.linalg.svd通过SVD构建主要组件。

当我使用sklearn从适合的PCA显示components_属性时,它们的大小与我手动计算的大小完全相同,但某些(不是全部)符号相反。造成这种情况的原因是什么?

更新:我的(部分)答案包含一些其他信息。

采用以下示例数据:

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]]

4 个答案:

答案 0 :(得分:7)

正如您在答案中所发现的那样,奇异值分解(SVD)的结果在奇异向量方面并不是唯一的。实际上,如果X的SVD是\ sum_1 ^ r \ s_i u_i v_i ^ \ top: enter image description here

随着s_i以递减方式排序,那么您可以看到您可以更改说u_1和v_1的符号(即"翻转"),减号将取消,因此公式仍将保留

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

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

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

答案 1 :(得分:2)

PCA在这里有3个维度,你基本上可以迭代地找到:1)保留最大方差的1D投影轴2)最大方差保持轴垂直于1)中的一个。第三个轴自动是与前两个轴垂直的轴。

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

答案 2 :(得分:2)

经过一番挖掘,我已经清除了一些但不是全部的混乱。 stats.stackexchange here已涵盖此问题。数学答案是“PCA是一个简单的数学变换。如果你改变了组件的符号,你就不会改变第一个组件中包含的方差。” 然而,在这种情况下(使用sklearn.PCA),歧义的来源更为具体:在PCA的来源(line 391)中,您拥有:< / p>
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。这是非常准确的,因为它没有sklearnsvd_solver参数,但确实有许多专门针对此目的的方法。

答案 3 :(得分:0)

对于那些关心目的而非数学部分的人来说,这是一个简短的通知。

虽然某些组件的符号相反,但不应将其视为问题。事实上,我们关心的事情(至少根据我的理解)是轴的方向。最终,组件是在使用pca转换输入数据之后识别这些轴的向量。因此,无论每个组件指向哪个方向,我们的数据所在的新轴都是相同的。