GPflow 和 Sklearn 计算的 PCA 不匹配
PCA computed by GPflow and Sklearn doesn't match
我正在使用 Sklearn and GPflow 执行 PCA 分析。我注意到两个库返回的输出不匹配。
请看下面的示例代码片段-
import numpy as np
from gpflow.models import PCA_reduce
from sklearn.decomposition import PCA
X = np.random.random((100, 10))
for n in range(1, 6):
X1 = PCA(n_components=n).fit_transform(X)
X2 = PCA_reduce(X, n)
print('[n=%d] allclose=%s' % (n, np.allclose(X1, X2)))
下面是输出-
[n=1] allclose=True
[n=2] allclose=False
[n=3] allclose=False
[n=4] allclose=False
[n=5] allclose=False
只有主成分个数为1时才会匹配,为什么会这样?
这里有两个不同的问题:
两种方法的特征值顺序相反。在 sklearn 实现中,特征向量按其特征值的大小递减排序,而在 gpflow 实现中,它们按大小递增排序。特别是,您应该将 PCA(n).fit_transform(X)
与 PCA_reduce(X, n)[:, ::-1]
进行比较。这当然也解释了为什么只使用一个组件就能得到你期望的结果。
然而,这本身是不够的:如果 $v$ 是长度为 1 且具有给定特征值的特征向量,那么 $-v$ 也是如此,因此您不能简单地使用 np.allclose
判断结果是否连贯;您需要考虑潜在的逆转。因此,您可以使用 a = np.all(np.isclose(X1, X2), 0)
之类的东西直接比较向量,b = np.all(np.isclose(X1, -X2), 0)
(注意减号)在 X2
中的所有向量都反转时比较它们,从那时起, a | b
成为他们同意逆转的条件。最后,np.all(a | b)
将检查这是否适用于每个特征向量。
确实,对您的测试进行的以下修改表明所有内容都是正确的:
In [74]: for n in range(1, 6):
...: X1 = PCA(n_components=n).fit_transform(X)
...: X2 = PCA_reduce(X, n)[:, ::-1]
...: print('[n=%d] allclose=%s' % (n, np.all(np.all(np.isclose(X1, X2), 0) | np.all(np.isclose(X1, -X2), 0))))
[n=1] allclose=True
[n=2] allclose=True
[n=3] allclose=True
[n=4] allclose=True
[n=5] allclose=True
我正在使用 Sklearn and GPflow 执行 PCA 分析。我注意到两个库返回的输出不匹配。
请看下面的示例代码片段-
import numpy as np
from gpflow.models import PCA_reduce
from sklearn.decomposition import PCA
X = np.random.random((100, 10))
for n in range(1, 6):
X1 = PCA(n_components=n).fit_transform(X)
X2 = PCA_reduce(X, n)
print('[n=%d] allclose=%s' % (n, np.allclose(X1, X2)))
下面是输出-
[n=1] allclose=True
[n=2] allclose=False
[n=3] allclose=False
[n=4] allclose=False
[n=5] allclose=False
只有主成分个数为1时才会匹配,为什么会这样?
这里有两个不同的问题:
两种方法的特征值顺序相反。在 sklearn 实现中,特征向量按其特征值的大小递减排序,而在 gpflow 实现中,它们按大小递增排序。特别是,您应该将
PCA(n).fit_transform(X)
与PCA_reduce(X, n)[:, ::-1]
进行比较。这当然也解释了为什么只使用一个组件就能得到你期望的结果。然而,这本身是不够的:如果 $v$ 是长度为 1 且具有给定特征值的特征向量,那么 $-v$ 也是如此,因此您不能简单地使用
np.allclose
判断结果是否连贯;您需要考虑潜在的逆转。因此,您可以使用a = np.all(np.isclose(X1, X2), 0)
之类的东西直接比较向量,b = np.all(np.isclose(X1, -X2), 0)
(注意减号)在X2
中的所有向量都反转时比较它们,从那时起,a | b
成为他们同意逆转的条件。最后,np.all(a | b)
将检查这是否适用于每个特征向量。
确实,对您的测试进行的以下修改表明所有内容都是正确的:
In [74]: for n in range(1, 6):
...: X1 = PCA(n_components=n).fit_transform(X)
...: X2 = PCA_reduce(X, n)[:, ::-1]
...: print('[n=%d] allclose=%s' % (n, np.all(np.all(np.isclose(X1, X2), 0) | np.all(np.isclose(X1, -X2), 0))))
[n=1] allclose=True
[n=2] allclose=True
[n=3] allclose=True
[n=4] allclose=True
[n=5] allclose=True