【问题标题】:In sklearn.decomposition.PCA, why are components_ negative?在 sklearn.decomposition.PCA 中,为什么 components_ 是负数?
【发布时间】:2017-11-29 15:29:46
【问题描述】:

我正在尝试跟随 Abdi & Williams - 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]]

【问题讨论】:

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


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

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

    随着 s_i 以递减的方式排序,那么您可以看到您可以更改 u_1 和 v_1 的符号(即“翻转”),减号将取消,因此公式仍然成立。

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

    由于 PCA 只是 X 的 SVD(或 X^\top X 的特征值分解),因此无法保证每次执行时不会在同一个 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 始终相同,因为符号上的不确定性已被消除。

    【讨论】:

    • @BradSolomon 如果可以的话,在这种情况下获得不确定的结果是否有用?
    • 这些仍然是确定性的——只是符号翻转是“基于U的决策”还是“基于V的决策”的问题。请参阅svd_flip 以供参考。我的观点是,我想做出基于 v 而不是基于 u 的决定。请参阅相关问题here。让我知道我是否有意义
    【解决方案3】:

    经过一番挖掘,我澄清了一些,但不是全部,我对此的困惑。此问题已在 stats.stackexchange here 中讨论。数学上的答案是“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 的实现并没有错,但我认为这并不是那么直观。任何熟悉贝塔(系数)概念的金融界人士都会知道,第一个主成分很可能类似于广泛的市场指数。问题是,sklearn 的实现会给你的第一个主成分带来很强的负负载。

    我的解决方案是一个没有实现svd_flip 的简单的version。它非常简单,因为它没有 sklearn 参数,例如 svd_solver,但确实有许多专门针对此目的的方法。

    【讨论】:

    • 按照惯例,奇异值都是正数并按大小排序。
    • @AryaMcCarthy 我不确定我是否关注你,你能进一步解释一下吗?奇异值是S。如果您查看 PCA codeS 向量没有被触及。 (在U, S, V = linalg.svd(X, full_matrices=False) 第 391 行之后已经是肯定的了。即使已经找到了解决方案,也正在操纵 UV,以“强制执行确定性输出”。
    【解决方案4】:

    使用 3 维 PCA,您基本上可以迭代地发现:1) 保留最大方差的一维投影轴 2) 垂直于 1 比一的最大方差保留轴。第三个轴自动与前两个轴垂直。

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

    【讨论】:

      猜你喜欢
      • 2011-04-22
      • 2016-02-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-11-16
      • 1970-01-01
      • 1970-01-01
      • 2011-04-06
      相关资源
      最近更新 更多