在sklearn.decomposition.PCA中,为什么components_是负数?
In sklearn.decomposition.PCA, why are components_ negative?
我正在尝试跟随 Abdi 和 Williams - Principal Component Analysis (2010) and build principal components through SVD, using numpy.linalg.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]]
使用这里的 3 维 PCA,您基本上可以迭代找到:1) 保留最大方差的 1D 投影轴 2) 最大方差保留轴垂直于 1) 中的一个。第三个轴自动垂直于前两个轴。
根据解释的方差列出了 components_。所以第一个解释了最大的差异,依此类推。请注意,根据 PCA 操作的定义,当您尝试在第一步中找到用于投影的向量时,它会最大化保留的方差,向量的符号无关紧要:让 M 成为您的数据矩阵(在您的情况下形状为 (20,3))。令 v1 为在投影数据时保留最大方差的向量。当您 select -v1 而不是 v1 时,您将获得相同的方差。 (你可以检查一下)。然后当 select 对第二个向量进行计算时,让 v2 成为垂直于 v1 并保持最大方差的向量。同样,selecting -v2 而不是 v2 将保留相同的方差量。然后可以将 v3 selected 为 -v3 或 v3。在这里,唯一重要的是 v1、v2、v3 构成数据 M 的正交基。符号主要取决于算法如何解决 PCA 运算背后的特征向量问题。特征值分解或 SVD 解的符号可能不同。
经过一些挖掘,我已经清除了一些(但不是全部)我对此的困惑。此问题已在 stats.stackexchange here. The mathematical answer is that "PCA is a simple mathematical transformation. If you change the signs of the component(s), you do not change the variance that is contained in the first component." However, in this case (with sklearn.PCA
), the source of ambiguity is much more specific: in the source (line 391) 上讨论,因为 PCA
您有:
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. But why the signs are being flipped to "ensure a deterministic输出,"我不确定。(U,S,V已经找到了在这一点上...)。因此,虽然 sklearn
的实现并没有错,但我认为它并不是那么直观。任何熟悉 beta(系数)概念的金融界人士都会知道第一个主成分很可能类似于大盘指数。问题是,sklearn
实施会给您带来对第一个主成分的强烈负负载。
我的解决方案是一个没有实现 svd_flip
的简化 version。它非常简单,因为它没有 sklearn
参数,例如 svd_solver
,但确实有许多专门用于此目的的方法。
正如您在回答中了解到的,奇异值分解 (SVD) 的结果在奇异向量方面并不是唯一的。事实上,如果 X 的 SVD 是 \sum_1^r \s_i u_i v_i^\top :
随着 s_i 以递减方式排列,然后您可以看到您可以更改 u_1 和 v_1 的符号(即 "flip"),减号将取消,因此公式仍然有效。
这表明 SVD 是唯一的直到左右奇异向量对的符号发生变化。
因为 PCA 只是 X 的 SVD(或 X^\top X 的特征值分解),所以不能保证它不会 return 每次在同一个 X 上得到不同的结果执行。可以理解,scikit learn 实现想要避免这种情况:他们保证左右奇异向量 returned(存储在 U 和 V 中)始终相同,通过强加(这是任意的)[ 的最大系数=28=]的绝对值为正。
正如您在阅读 the source 中看到的那样:首先他们使用 linalg.svd()
计算 U 和 V。然后,对于每个向量 u_i(即 U 的行),如果其最大元素的绝对值是正数,则它们什么都不做。否则,他们将 u_i 更改为 - u_i,并将相应的左奇异向量 v_i 更改为 - v_i。如前所述,这不会更改 SVD 公式,因为减号抵消了。但是,现在可以保证经过此处理后的 U 和 V return 始终相同,因为符号上的不确定性已被删除。
对于那些关心目的而不关心数学部分的人来说,这是一个简短的通知。
虽然某些组件的符号相反,但这不应该被视为问题。事实上,我们真正关心的(至少在我看来)是坐标轴的方向。这些组件最终是在使用 pca 转换输入数据后识别这些轴的向量。因此,无论每个组件指向哪个方向,我们的数据所在的新轴都是相同的。
我正在尝试跟随 Abdi 和 Williams - Principal Component Analysis (2010) and build principal components through SVD, using numpy.linalg.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]]
使用这里的 3 维 PCA,您基本上可以迭代找到:1) 保留最大方差的 1D 投影轴 2) 最大方差保留轴垂直于 1) 中的一个。第三个轴自动垂直于前两个轴。
根据解释的方差列出了 components_。所以第一个解释了最大的差异,依此类推。请注意,根据 PCA 操作的定义,当您尝试在第一步中找到用于投影的向量时,它会最大化保留的方差,向量的符号无关紧要:让 M 成为您的数据矩阵(在您的情况下形状为 (20,3))。令 v1 为在投影数据时保留最大方差的向量。当您 select -v1 而不是 v1 时,您将获得相同的方差。 (你可以检查一下)。然后当 select 对第二个向量进行计算时,让 v2 成为垂直于 v1 并保持最大方差的向量。同样,selecting -v2 而不是 v2 将保留相同的方差量。然后可以将 v3 selected 为 -v3 或 v3。在这里,唯一重要的是 v1、v2、v3 构成数据 M 的正交基。符号主要取决于算法如何解决 PCA 运算背后的特征向量问题。特征值分解或 SVD 解的符号可能不同。
经过一些挖掘,我已经清除了一些(但不是全部)我对此的困惑。此问题已在 stats.stackexchange here. The mathematical answer is that "PCA is a simple mathematical transformation. If you change the signs of the component(s), you do not change the variance that is contained in the first component." However, in this case (with sklearn.PCA
), the source of ambiguity is much more specific: in the source (line 391) 上讨论,因为 PCA
您有:
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. But why the signs are being flipped to "ensure a deterministic输出,"我不确定。(U,S,V已经找到了在这一点上...)。因此,虽然 sklearn
的实现并没有错,但我认为它并不是那么直观。任何熟悉 beta(系数)概念的金融界人士都会知道第一个主成分很可能类似于大盘指数。问题是,sklearn
实施会给您带来对第一个主成分的强烈负负载。
我的解决方案是一个没有实现 svd_flip
的简化 version。它非常简单,因为它没有 sklearn
参数,例如 svd_solver
,但确实有许多专门用于此目的的方法。
正如您在回答中了解到的,奇异值分解 (SVD) 的结果在奇异向量方面并不是唯一的。事实上,如果 X 的 SVD 是 \sum_1^r \s_i u_i v_i^\top :
随着 s_i 以递减方式排列,然后您可以看到您可以更改 u_1 和 v_1 的符号(即 "flip"),减号将取消,因此公式仍然有效。
这表明 SVD 是唯一的直到左右奇异向量对的符号发生变化。
因为 PCA 只是 X 的 SVD(或 X^\top X 的特征值分解),所以不能保证它不会 return 每次在同一个 X 上得到不同的结果执行。可以理解,scikit learn 实现想要避免这种情况:他们保证左右奇异向量 returned(存储在 U 和 V 中)始终相同,通过强加(这是任意的)[ 的最大系数=28=]的绝对值为正。
正如您在阅读 the source 中看到的那样:首先他们使用 linalg.svd()
计算 U 和 V。然后,对于每个向量 u_i(即 U 的行),如果其最大元素的绝对值是正数,则它们什么都不做。否则,他们将 u_i 更改为 - u_i,并将相应的左奇异向量 v_i 更改为 - v_i。如前所述,这不会更改 SVD 公式,因为减号抵消了。但是,现在可以保证经过此处理后的 U 和 V return 始终相同,因为符号上的不确定性已被删除。
对于那些关心目的而不关心数学部分的人来说,这是一个简短的通知。
虽然某些组件的符号相反,但这不应该被视为问题。事实上,我们真正关心的(至少在我看来)是坐标轴的方向。这些组件最终是在使用 pca 转换输入数据后识别这些轴的向量。因此,无论每个组件指向哪个方向,我们的数据所在的新轴都是相同的。