Ответ 1
Это поведение, по общему признанию, потенциально странно, но тем не менее оно документировано в документах соответствующих функций.
Класс 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.decomposition не позволяет восстановить исходные данные из отбеленной матрицы, , поскольку сингулярные значения центрированных данных/собственные значения ковариационной матрицы представляют собой мусор, собранный после функции 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
Как видно из строки, создающей 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)
Заключение. Получив сингулярные значения центрированной матрицы данных, мы можем отменить отбеливание и преобразовать обратно в исходное пространство. Однако эта функция не реализована в объекте PCA
.
Устранение. Без изменения кода scikit learn (что может быть сделано официально, если оно считается полезным для сообщества), решение, которое вы ищете, - это (и теперь я буду использовать ваш код и имена переменных, проверьте, работает ли это для вас):
transformed_a = p.transform(a)
singular_values = 1. / np.sqrt((p.components_ ** 2).sum(axis=1) / len(x))
inverse_transformed = np.dot(transformed_a, singular_values[:, np.newaxis] ** 2 *
p.components_ / len(x)) + p.mean_)
(IMHO функция inverse_transform
любой оценки должна вернуться как можно ближе к исходным данным. В этом случае не стоило бы слишком сильно хранить сингулярные значения, поэтому, возможно, эта функциональность действительно должна быть добавлена к sklearn.)
EDIT Особые значения центрированной матрицы не являются сборкой мусора, как первоначально предполагалось. На самом деле, они хранятся в pca.explained_variance_
и могут использоваться для небезопасности. См. Комментарии.