Инвертирующее преобразование PCA с помощью sklearn (с whiten=True)
обычно преобразование PCA легко инвертируется:
import numpy as np
from sklearn import decomposition
x = np.zeros((500, 10))
x[:, :5] = random.rand(500, 5)
x[:, 5:] = x[:, :5] # so that using PCA would make sense
p = decomposition.PCA()
p.fit(x)
a = x[5, :]
print p.inverse_transform(p.transform(a)) - a # this yields small numbers (about 10**-16)
теперь, если мы попытаемся добавить параметр whiten=True, результат будет совершенно другим:
p = decomposition.PCA(whiten=True)
p.fit(x)
a = x[5, :]
print p.inverse_transform(p.transform(a)) - a # now yields numbers about 10**15
Итак, поскольку я не нашел никаких других методов, которые могли бы сделать трюк, я удивляюсь, как можно получить исходное значение a? Или это вообще возможно? Большое спасибо за любую помощь.
2 ответов
это поведение, по общему признанию, потенциально странно, но тем не менее документировано в документах соответствующих функций.
класс docstring PCA
о whiten
:
whiten : bool, optional
When True (False by default) the `components_` vectors are divided
by n_samples times singular values to ensure uncorrelated outputs
with unit component-wise variances.
Whitening will remove some information from the transformed signal
(the relative variance scales of the components) but can sometime
improve the predictive accuracy of the downstream estimators by
making there data respect some hard-wired assumptions.
код и docstring PCA.inverse_transform
говорит:
def inverse_transform(self, X):
"""Transform data back to its original space, i.e.,
return an input X_original whose transform would be X
Parameters
----------
X : array-like, shape (n_samples, n_components)
New data, where n_samples is the number of samples
and n_components is the number of components.
Returns
-------
X_original array-like, shape (n_samples, n_features)
Notes
-----
If whitening is enabled, inverse_transform does not compute the
exact inverse operation as transform.
"""
return np.dot(X, self.components_) + self.mean_
теперь посмотрите, что происходит, когда whiten=True
функции PCA._fit
:
if self.whiten:
self.components_ = V / S[:, np.newaxis] * np.sqrt(n_samples)
else:
self.components_ = V
здесь S
являются сингулярными значениями и V
являются сингулярными векторами. По определению, отбеливание выравнивает спектр, по существу устанавливая все собственные значения ковариационной матрицы на 1
.
для того, чтобы наконец-то ответьте на свой вопрос: элемент PCA
объект sklearn.декомпозиция не позволяет восстановить исходные данные из отбеленной матрицы,потому что сингулярные значения центрированных данных собственных значений ковариационной матрицы собирают мусор после функции PCA._fit
.
, если вы получите сингулярные значения S
вручную, вы сможете умножить их обратно и вернуться к исходным данным.
попробуй такое
import numpy as np
rng = np.random.RandomState(42)
n_samples_train, n_features = 40, 10
n_samples_test = 20
X_train = rng.randn(n_samples_train, n_features)
X_test = rng.randn(n_samples_test, n_features)
from sklearn.decomposition import PCA
pca = PCA(whiten=True)
pca.fit(X_train)
X_train_mean = X_train.mean(0)
X_train_centered = X_train - X_train_mean
U, S, VT = np.linalg.svd(X_train_centered, full_matrices=False)
components = VT / S[:, np.newaxis] * np.sqrt(n_samples_train)
from numpy.testing import assert_array_almost_equal
# These assertions will raise an error if the arrays aren't equal
assert_array_almost_equal(components, pca.components_) # we have successfully
# calculated whitened components
transformed = pca.transform(X_test)
inverse_transformed = transformed.dot(S[:, np.newaxis] ** 2 * pca.components_ /
n_samples_train) + X_train_mean
assert_array_almost_equal(inverse_transformed, X_test) # We have equality
как вы можете видеть из строки creating inverse_transformed
, если вы умножите сингулярные значения обратно на компоненты, вы можете вернуться в исходное пространство.
на самом деле, сингулярные значения S
на самом деле скрыто в нормы компонентов, поэтому нет необходимости вычислять SVD вдоль стороны PCA
. Используя определения выше, можно увидеть
S_recalculated = 1. / np.sqrt((pca.components_ ** 2).sum(axis=1) / n_samples_train)
assert_array_almost_equal(S, S_recalculated)
вывод: получив сингулярные значения центрированной матрицы данных, мы можем отменить отбеливание и преобразовать обратно в исходное пространство. Однако эта функциональность изначально не реализована в
self.components_
первоначально является Eignenvectors, которые подлежат
>>> np.allclose(self.components_.T, np.linalg.inv(self.components_))
True
в проект(transform
на sklearn
) к этим компонентам, PCA вычитание их self.mean_
и умножение self.components_
as
Y = np.dot(X - self.mean_, self.components_.T)
=> Y = (X - mean) * V.T # rewritten for simple notation
здесь X
- это образцы, mean
является средним из учебных образцов, и V
является основными компонентами.
затем реконструкция(inverse_transform
на sklearn
) следующим образом (к get Y
С X
)
Y = (X - mean) * V.T
=> Y*inv(V.T) = X - mean
=> Y*V = X - mean # inv(V.T) = V
=> X = Y*V + mean
=> Xrec = np.dot(X, self.components_) + self.mean_
проблема self.components_
of whiten
PCA не подлежит
>>> np.allclose(self.components_.T, np.linalg.inv(self.components_))
False
вы можете вывести причину почему из кода @eickenberg.
Итак, вам нужно изменить sklearn.decomposition.pca
-
код сохраняет
the reconstruction matrix
.self.components_
ofwhiten PCA
иself.components_ = V / S[:, np.newaxis] * np.sqrt(n_samples)
таким образом, мы можем назначить
the reconstruction matrix
asself.recons_ = V * S[:, np.newaxis] / np.sqrt(n_samples)
-
когда
inverse_transform
вызывается, мы вернем результат, полученный этой матрицей, какif self.whiten: return np.dot(X, self.recons_) + self.mean_
вот и все. Давайте проверим.
>>> p = decomposition.PCA(whiten=True)
>>> p.fit(x)
>>> np.allclose(p.inverse_transform(p.transform(a)), a)
True
извините за мой английский. Пожалуйста, улучшите этот пост, я не уверен, что выражения тезисов верны.