通常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
所以,由于我没有找到任何其他方法可以解决这个问题,我觉得如何才能获得原始值?或者它甚至可能吗?非常感谢您的帮助。
答案 0 :(得分:14)
这种行为无疑是可能很奇怪的,但它仍记录在相关功能的文档字符串中。
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.
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
。
为了最终回答您的问题:sklearn.decomposition的PCA
对象不允许从白化矩阵重建原始数据,因为居中的奇异值数据/协方差矩阵的特征值在函数 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
实际上隐藏在组件的范数中,因此无需计算PCA
旁边的SVD。使用上面的定义可以看到
S_recalculated = 1. / np.sqrt((pca.components_ ** 2).sum(axis=1) / n_samples_train)
assert_array_almost_equal(S, S_recalculated)
结论:通过获取居中数据矩阵的奇异值,我们可以撤消白化并转换回原始空间。但是,此功能未在PCA
对象中本机实现。
补救措施:无需修改scikit的代码(如果社区认为有用,可以正式完成),您正在寻找的解决方案就是这个(和我现在将使用您的代码和变量名称,请检查这是否适用于您):
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_)
(恕我直言,任何估算器的inverse_transform
函数都应尽可能接近原始数据。在这种情况下,明确存储奇异值也不会花费太多,所以这个功能实际应该是添加到sklearn。)
编辑中心矩阵的奇异值不是最初想到的垃圾收集。事实上,它们存储在pca.explained_variance_
中,可以用来解决问题。见评论。
答案 1 :(得分:4)
self.components_
最初是Eignenvectors,受
>>> np.allclose(self.components_.T, np.linalg.inv(self.components_))
True
要将(transform
)sklearn
投射到这些组件,PCA 减去他们的self.mean_
和倍增 {{1}作为
self.components_
其中 Y = np.dot(X - self.mean_, self.components_.T)
=> Y = (X - mean) * V.T # rewritten for simple notation
是样本,X
是训练样本的平均值,mean
是主要成分。
然后重建(V
中的inverse_transform
)如下(从sklearn
获取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_
PCA不受
whiten
您可以从@eickenberg的代码中找出为什么的原因。
因此,您需要修改>>> np.allclose(self.components_.T, np.linalg.inv(self.components_))
False
代码保留sklearn.decomposition.pca
。 the reconstruction matrix
的{{1}}是
self.components_
因此我们可以将whiten PCA
指定为
self.components_ = V / S[:, np.newaxis] * np.sqrt(n_samples)
调用the reconstruction matrix
时,我们将返回此矩阵派生的结果
self.recons_ = V * S[:, np.newaxis] / np.sqrt(n_samples)
就是这样。我们来试试吧。
inverse_transform
抱歉我的英文。请改进这篇文章我不确定这些表达是否正确。