我试图跟随Abdi & Williams - 主成分分析 (2010年),并使用numpy.linalg.svd通过SVD构建主组件。
当我显示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]]发布于 2017-06-30 12:56:31
正如您在回答中指出的,奇异值分解(SVD)的结果在奇异向量方面并不是唯一的。实际上,如果X的SVD是\sum_1^r \s_i u_i v_i^\top:

当s_i以递减的方式排列时,您可以看到您可以更改u_1和v_1的符号(即“翻转”),减号将取消,因此公式仍然有效。
这表明SVD是唯一的,直到左、右奇异向量成对的符号变化为止。
由于PCA只是X的一个SVD (或X^\顶X的特征值分解),因此不能保证它每次执行时都不会在同一个X上返回不同的结果。可以理解的是,scikit学习实现想要避免这种情况:它们保证返回的左、右奇异向量(存储在U和V中)总是相同的,方法是(这是任意的),使u_i的最大绝对值系数为正。
正如您所看到的,阅读来源:首先,他们用linalg.svd()计算U和V。然后,对于每个向量u_i (即U的行),如果其绝对值中的最大元素为正,则它们什么也不做。否则,它们将u_i改为- u_i,并将相应的左奇异向量v_i改为- v_i。正如前面所述,这不会改变SVD公式,因为减号抵消了。然而,现在保证在这个处理后返回的U和V总是相同的,因为符号上的不确定性已经消除了。
发布于 2017-06-26 23:23:44
经过一番挖掘,我澄清了一些,但不是全部,我在这个问题上的困惑。这个问题已经在stats.stackexchange 这里上讨论过了。数学上的答案是:"PCA是一种简单的数学变换,如果改变了分量的符号,就不会改变包含在第一个分量中的方差。“但是,在这种情况下(使用sklearn.PCA),歧义的来源要具体得多:在PCA的源(第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被定义为这里。但是,我不确定为什么这些标志被转换为“确保确定性输出”。(U,S,V在这一点上已经找到)。因此,尽管sklearn的实施并不是不正确的,但我不认为这完全是凭直觉的。任何熟悉贝塔(系数)概念的金融界人士都会知道,第一个主成分最有可能类似于一个广泛的市场指数。问题是,sklearn的实施会给第一个主成分带来强大的负负荷。
我的解决方案是一个不实现版本的哑弹式svd_flip。它非常简单,因为它没有sklearn参数(如svd_solver ),但确实有许多专门针对此目的的方法。
发布于 2017-06-26 18:21:48
用这里的PCA在三维空间中,你基本上可以迭代地找到: 1)最大方差保持的一维投影轴,2)垂直于1的最大方差保持轴。第三轴是垂直于前两轴的轴。
根据解释的方差列出components_。第一个解释了最大的方差,依此类推。注意,通过PCA操作的定义,当您试图在第一步找到投影向量时,最大限度地保留了方差,向量的符号并不重要:让M作为您的数据矩阵(在您的情况下,它的形状为(20,3))。当数据被投影时,设v1是保持最大方差的向量。当您选择-v1而不是v1时,您将获得相同的方差。(你可以看看这个)。然后,在选择第二个向量时,设v2为垂直于v1的向量,并保持最大方差。同样,选择-v2而不是v2将保持相同的方差。然后,可以选择v3作为-v3或v3。在这里,唯一重要的是v1,v2,v3构成了一个正交基,对于M数据,符号主要取决于算法如何解决PCA运算背后的特征向量问题。特征值分解或SVD解在符号上可能有所不同。
https://stackoverflow.com/questions/44765682
复制相似问题