Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/python-2.7/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 2.7 使用sklearn反演PCA变换(whiten=True)_Python 2.7_Scikit Learn_Pca - Fatal编程技术网

Python 2.7 使用sklearn反演PCA变换(whiten=True)

Python 2.7 使用sklearn反演PCA变换(whiten=True),python-2.7,scikit-learn,pca,Python 2.7,Scikit Learn,Pca,通常,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_trans

通常,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的原始值?或者甚至有可能吗?非常感谢您的帮助。

这种行为无疑有可能很奇怪,但相关函数的文档字符串中记录了它

PCA
的类docstring说明了以下关于
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_
现在看看在函数
PCA中
whiten=True
时会发生什么情况

    if self.whiten:
        self.components_ = V / S[:, np.newaxis] * np.sqrt(n_samples)
    else:
        self.components_ = V
其中,
S
为奇异值,
V
为奇异向量。根据定义,白化对光谱进行分级,基本上将协方差矩阵的所有特征值设置为
1

为了最后回答您的问题,sklearn.decomposition的
PCA
对象不允许从白化矩阵重建原始数据,因为中心数据的奇异值/协方差矩阵的特征值在函数
PCA.\u 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
正如您从创建
逆变换
的行中所看到的,如果将奇异值乘以组件,则可以返回原始空间

事实上,奇异值
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 learn的代码的情况下(如果社区认为有用,可以正式进行),您正在寻找的解决方案是(现在我将使用您的代码和变量名,请检查这是否适用于您):

(任何估计器的
逆变换
函数应尽可能回到原始数据。在这种情况下,显式存储奇异值不会花费太多,因此,可能该功能实际上应该添加到sklearn中。)


编辑居中矩阵的奇异值不会像最初认为的那样被垃圾收集。事实上,它们存储在pca.explained\u variance\uuu
中,可用于解除伤害。请参阅注释。

self.components\u
最初是受

>>> np.allclose(self.components_.T, np.linalg.inv(self.components_))
True
>>> np.allclose(self.components_.T, np.linalg.inv(self.components_))
False
要将(
transform
in
sklearn
)投影到这些组件,PCA减去它们的
self.mean,然后乘以它们的
self.components

   Y = np.dot(X - self.mean_, self.components_.T) 
=> Y = (X - mean) * V.T # rewritten for simple notation
self.recons_ = V * S[:, np.newaxis] / np.sqrt(n_samples)
其中,
X
是样本,
mean
是训练样本的平均值,
V
是主成分

然后,重构
sklearn
中的
逆变换
)如下所示(从
X
获取
Y


问题是
self.
whiten
PCA的组件不受

>>> np.allclose(self.components_.T, np.linalg.inv(self.components_))
True
>>> np.allclose(self.components_.T, np.linalg.inv(self.components_))
False
您可以从@Eikenberg的代码中导出原因为什么

因此,您需要修改
sklearn.decomposition.pca

  • 代码保留重建矩阵
  • <代码>自身。
    美白PCA的组件

    self.components_ = V / S[:, np.newaxis] * np.sqrt(n_samples)
    
    因此,我们可以将重构矩阵分配为

       Y = np.dot(X - self.mean_, self.components_.T) 
    => Y = (X - mean) * V.T # rewritten for simple notation
    
    self.recons_ = V * S[:, np.newaxis] / np.sqrt(n_samples)
    
  • 调用
    逆_变换
    时,我们将返回由该矩阵导出的结果,如下所示

    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
    

    对不起我的英语。请改进此帖子,我不确定这些表达式是否正确。

    PCA
    对象有一个关键字参数
    n\u components
    。如果设置了此选项,则您的第一个条件将不会呈现
    True
    (同样在SVD中,关键字
    full\u matrix=False
    可能导致非平方矩阵)。您的解决方案似乎向scikit学习包添加了代码。如果您感兴趣,您应该通过向社区提出请求的方式向社区提出。但是,可能需要进行一些更改,因为您的代码现在的方式是复制组件,这是低效的。一旦删除,这可能会很有趣。再次查看您的帖子,您可能应该使用
    inv
    编辑掉调用以反转
    组件
    向量,因为它通常没有很好的定义。伪逆
    pinv
    将在非平方情况下工作,但我不确定结果是否理想。非常感谢,这非常有效。我以前在R中使用PCA,无论组件是否被重新调整为具有单位方差,它都能够反转转换,因此我非常惊讶地发现sklearn无法这样做。我也很惊讶。它被明确记录的事实表明,它背后有一个原因。如果没有,我认为应该更改。重新阅读您的评论,准确地说,增白不仅仅是将组件转换为单位方差(这可以通过
    sklearn.preprocessing.StandardScaler轻松完成,也可以轻松地进行逆变换)。这是高斯意义上的去相关:白色特征的协方差矩阵将是对角的。顺便说一句,实际上不需要知道
    len(x)
    参数(它被取消了)