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 ответ

Решение

Здесь сговорились две разные проблемы:

  1. Порядок собственных значений обратный для двух методов. В реализации sklearn собственные векторы упорядочены по убыванию величины их собственного значения, в то время как в реализации gpflow они упорядочены по возрастанию величины. В частности, вы должны сравнивать PCA(n).fit_transform(X) в PCA_reduce(X, n)[:, ::-1], Это, конечно, также объясняет, почему вы получаете то, что ожидаете, используя только один компонент.

  2. Однако одного этого недостаточно: если $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
Другие вопросы по тегам