PCA, вычисленный GPflow, и Sklearn не совпадает
Я выполняю анализ PCA с использованием Sklearn и GPflow. Я заметил, что выходные данные, возвращаемые обеими библиотеками, не совпадают.
Пожалуйста, смотрите ниже пример кода
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. Почему такое поведение?
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