归因分析笔记4:PCA逆变换

目录

PCA转回原特征

例1

例2

scikit-learn中的PCA

PCA的对象

PCA对象的方法

PCA.components_

总结

PCA过程

PCA转回原特征的公式

手刻逆转换

Sklearn逆转换

PCA逆转换实验

sklearn的逆转换

手刻PCA以及逆转换


PCA转回原特征

例1

参考:

https://www.cnpython.com/qa/81148

sklearn的PCA 转换是怎样手算, 如何执行反变换。pca对象的哪个字段包含反变换的相关系数?如何计算反变换?

具体来说,我指的是sklearn.decomposition.PCA package中提供的PCA.inverse_transform()方法调用:如何使用PCA计算的各种系数重现其功能?

1)transform不是data * pca.components_。

首先,*不是numpy数组的点积。这是元素相乘。要执行点积,需要使用np.dot。

其次,PCA.components_的形状是(n个组件,n个特征),而要转换的数据形状是(n个样本,n个特征),因此需要对PCA.components_进行转置才能执行点积。

此外,变换的第一步是减去平均值,因此,如果手动进行,也需要首先减去平均值。

正确的转换方法是

data_reduced = np.dot(data - pca.mean_, pca.components_.T)

2)inverse_transform只是transform的逆过程

data_original = np.dot(data_reduced, pca.components_) + pca.mean_

如果您的数据在每一列中的平均值已经为零,那么您可以忽略上面的pca.mean_

在Scikit中,pca.components_就是P的逆矩阵, 逆转换时PCA.components不用求逆

import numpy as np

from sklearn.decomposition import PCA

pca = PCA(n_components=3)

pca.fit(data)

data_reduced = np.dot(data, pca.components_.T) # transform

data_original = np.dot(data_reduced, pca.components_) # inverse_transform

例2

参考:

https://www.cnblogs.com/okokok/p/6822885.html

在Scikit中运用PCA很简单

import numpy as np

from sklearn import decomposition

from sklearn import datasets

iris = datasets.load_iris()

X = iris.data

y = iris.target

pca = decomposition.PCA(n_components=3)

pca.fit(X)

X = pca.transform(X)

以上代码是将含有4个特征的数据经过PCA压缩为3个特征。PCA的压缩由如下特点:

1.新的3个特征并不是随便删除一个特征后留下的,而是4个特征的线性组合。

2.新的3个特征保留了原有4个特征的绝大部分信息,换句话说就是略有损失。

那么PCA的损失到底是什么? 新特征能否转回旧特征?

首先看PCA过程:

PCA过程

1.均值化矩阵X

2.通过一系列矩阵运算得出  特征矩阵P

3.矩阵运算 Y = P * X

Y 即为原始数据降维后的结果,也就是说,得到矩阵P后,我们还可以通过Y=P * X这个算式, 反推回X

 Y = P * X ==>   P(-1) * Y = P(-1) * P * X,  P(-1)是P的逆矩阵, 即 P(-1) * P = 1

                ==>   P(-1) * Y = X

需要注意的是,程序一开始就已经将原始数据均值化,所以实际上, P(-1)*Y的结果需要去均值化才是原来的样子

在Scikit中,pca.components_就是P的逆矩阵

转换过程源码:

1    def transform(self, X, y=None):

 2         """Apply dimensionality reduction to X.

 3

 4         X is projected on the first principal components previously extracted

 5         from a training set.

 6

 7         Parameters

 8         ----------

 9         X : array-like, shape (n_samples, n_features)

10             New data, where n_samples is the number of samples

11             and n_features is the number of features.

12

13         Returns

14         -------

15         X_new : array-like, shape (n_samples, n_components)

16

17         Examples

18         --------

19

20         >>> import numpy as np

21         >>> from sklearn.decomposition import IncrementalPCA

22         >>> X = np.array([[-1, -1], [-2, -1], [-3, -2], [1, 1], [2, 1], [3, 2]])

23         >>> ipca = IncrementalPCA(n_components=2, batch_size=3)

24         >>> ipca.fit(X)

25         IncrementalPCA(batch_size=3, copy=True, n_components=2, whiten=False)

26         >>> ipca.transform(X) # doctest: +SKIP

27         """

28         check_is_fitted(self, ['mean_', 'components_'], all_or_any=all)

29         print self.mean_

30         X = check_array(X)

31         if self.mean_ is not None:

32             X = X - self.mean_

33         X_transformed = fast_dot(X, self.components_.T)

34         if self.whiten:

35             X_transformed /= np.sqrt(self.explained_variance_)

36         return X_transformed

还原降维前数据:

iris = datasets.load_iris()

X = iris.data

y = iris.target

print X[0]

pca = decomposition.PCA(n_components=3)

pca.fit(X)

X = pca.transform(X)

a = np.matrix(X)

b = np.matrix(pca.components_)

c = a * b

mean_of_data = np.matrix([5.84333333, 3.054,       3.75866667,  1.19866667])

print c[0]

print c[0] + mean_of_data

scikit-learn中的PCA

PCA.inverse_transform()

X=pca.inverse_transform(newX)

将降维后的数据转换成原始数据

X=scaler.inverse_transform(X[, copy])

将标准化后的数据转换为标准化之前的原始数据。

参考博文:

https://blog.csdn.net/u012162613/article/details/42192293

scikit-learn官方文档:

https://scikit-learn.org/stable/modules/generated/sklearn.decomposition.PCA.html#sklearn.decomposition.PCA

PCA的对象

components_ :返回具有最大方差的成分。

explained_variance_ratio_:返回所保留的n个成分各自的方差百分比。即每个成分(新特征)的方差大小

n_components_:返回所保留的成分个数n。

mean_:每个特征的均值

noise_variance_:

PCA对象的方法

fit(X,y=None)

fit()可以说是scikit-learn中通用的方法,每个需要训练的算法都会有fit()方法,它其实就是算法中的“训练”这一步骤。因为PCA是无监督学习算法,此处y自然等于None。

fit(X),表示用数据X来训练PCA模型。

函数返回值:调用fit方法的对象本身。比如pca.fit(X),表示用X对pca这个对象进行训练。

fit_transform(X)

用X来训练PCA模型,同时返回降维后的数据。

newX=pca.fit_transform(X),newX就是降维后的数据。

inverse_transform()

将降维后的数据转换成原始数据,将数据转换回其原始空间X=pca.inverse_transform(newX)

transform(X)

将数据X转换成降维后的数据。当模型训练好后,对于新输入的数据,都可以用transform方法来降维。

例子

>>> pca.n_components

1

>>> pca.explained_variance_ratio_

array([ 0.99910873])

>>> pca.explained_variance_

array([ 2.55427003])

>>> pca.get_params

<bound method PCA.get_params of PCA(copy=True, n_components=1, whiten=False)>

训练的pca对象的n_components值为1,即保留1个特征,该特征的方差为2.55427003,占所有特征的方差百分比为0.99910873,意味着几乎保留了所有的信息。get_params返回各个参数的值。

PCA.components_

核实PCA.components_中数值的意义

看公式推导, components的逆和转置是等价的吗?

PCA算法认为降维就是线性function,输入x与输出z之间是线性变换(linear transform),PCA 目标: 找变换系数W.

z=wx

从n个特征转换到m个特征:

$$ z_{1} = w^{1} \cdot x,\\ z_{2} = w^{2} \cdot x,\\ W = \begin{bmatrix} \left( w^{1} \right)^{T} \\ \left( w^{2} \right)^{T} \\  \vdots \\ \end{bmatrix} \\ \\ \Rightarrow  z = Wx \\ \begin{bmatrix}  z_{1} \\  z_{2} \\  \vdots \\ z_{m}\end{bmatrix} =\begin{bmatrix} \left( w^{1} \right)^{T} \\ \left( w^{2} \right)^{T} \\  \vdots \\ \end{bmatrix} \begin{bmatrix}  x_{1} \\  x_{2} \\  \vdots \\ x_{n}\end{bmatrix} \\ \Rightarrow  \begin{bmatrix}  z_{1} \\  z_{2} \\  \vdots \\ z_{m}\end{bmatrix} =\begin{bmatrix} w^{1}_{1} & w^{1}_{2} & \cdots  & w^{1}_{n} \\w^{2}_{1} & w^{2}_{2} & \cdots &w^{2}_{n}\\ & \vdots \\ w^{m}_{1} & w^{m}_{2} & \cdots &w^{m}_{n}\end{bmatrix} \begin{bmatrix}  x_{1} \\  x_{2} \\  \vdots \\  x_{n}\end{bmatrix}  \\ \Rightarrow  \begin{bmatrix}  z_{1} \\  z_{2} \\  \vdots \\ z_{m}\end{bmatrix} =\begin{bmatrix} w^{1}_{1} x_{1}+ w^{1}_{2}x_{2} + \cdots +w^{1}_{n}x_{n}  \\w^{2}_{1} x_{1}+ w^{2}_{2} x_{2}+ \cdots +w^{2}_{n}x_{n} \\  \vdots \\ w^{m}_{1} x_{1}+ w^{m}_{2} x_{2}+ \cdots   +w^{m}_{n}x_{n}\end{bmatrix}$$

其中每个组件为一个w^i, 考虑x中的所有特征, 形成z中的一个特征

PCA.components_.T的形状是

W(m个组件, n个特征)对应X(n个特征, k个样本)

components的逆和转置等价

因为变换矩阵W是正交阵, 正交阵的逆等于它的转置.

证明

单位正交矩阵:

$$ Q=\left[  \begin{matrix}    \vdots & \vdots &  & \vdots \\    q_1 & q_2& \dots & q_n \\    \vdots & \vdots & & \vdots \\   \end{matrix}   \right] , q_i^Tq_j=\left\{ \begin{aligned} 0 & \ &when \  i\neq j \\ 1 & \ & when \ i=j \end{aligned} \right. \\ Q^TQ=\left[ \begin{matrix}q_1^T \\ q_2^T \\ \vdots \\ q_n^T \end{matrix} \right] \left[ \begin{matrix} q_1^T q_2^T \dots q_n^T\end{matrix} \right]=I $$

总结

PCA过程

1.均值化矩阵X

2.通过一系列矩阵运算得出  特征矩阵P

3.矩阵运算 Y = P * X

PCA转回原特征的公式

Y 即为原始数据降维后的结果,也就是说,得到矩阵P后,我们还可以通过Y=P * X这个算式, 反推回X

 Y = P * X ==>   P(-1) * Y = P(-1) * P * X,  P(-1)是P的逆矩阵, 即 P(-1) * P = 1

                ==>   P(-1) * Y = X

需要注意的是,程序一开始就已经将原始数据均值化,所以实际上, P(-1)*Y的结果需要去均值化才是原来的样子

手刻逆转换

iris = datasets.load_iris()

X = iris.data

y = iris.target

print X[0]

pca = decomposition.PCA(n_components=3)

pca.fit(X)

X = pca.transform(X)

a = np.matrix(X)

b = np.matrix(pca.components_)

c = a * b

mean_of_data = np.matrix([5.84333333, 3.054,       3.75866667,  1.19866667])

print c[0]

print c[0] + mean_of_data

Sklearn逆转换

X=scaler.inverse_transform(X[, copy])

将标准化后的数据转换为原始数据。

X=pca.inverse_transform(newX)

将降维后的数据转换成原始数据

PCA逆转换实验

创建pcaInverseDemo.py进行尝试

先试一下调包

sklearn的逆转换

建立简单矩阵, PCA转换, 输出值

import numpy as np

from sklearn import decomposition

# 建立简单矩阵

X = np.array([[-1, -1], [-2, -1], [-3, -2], [1, 1], [2, 1], [3, 2]])

# 将含有2个特征的数据经过PCA压缩为1个特征

pca = decomposition.PCA(n_components=1)

pca.fit(X)

X_pca = pca.transform(X)

print("X_pca:\n",X_pca)

X_pca:

 [[ 1.38340578]

 [ 2.22189802]

 [ 3.6053038 ]

 [-1.38340578]

 [-2.22189802]

 [-3.6053038 ]]

再逆转换, 输出值

X_origin=pca.inverse_transform(X_pca)

X_origin:

 [[-1.15997501 -0.75383654]

 [-1.86304424 -1.21074232]

 [-3.02301925 -1.96457886]

 [ 1.15997501  0.75383654]

 [ 1.86304424  1.21074232]

 [ 3.02301925  1.96457886]]

如果维度降低, 则会损失信息, 如果进行PCA时维度不变, 则逆转换后值与原来相同

手刻PCA以及逆转换

PCA:

def pca(X, k): # k is the components you want

    # mean of each feature

    n_samples, n_features = X.shape

    mean = np.array([np.mean(X[:, i]) for i in range(n_features)])

    # normalization

    norm_X = X - mean

    # scatter matrix

    scatter_matrix = np.dot(np.transpose(norm_X), norm_X)

    # Calculate the eigenvectors and eigenvalues

    eig_val, eig_vec = np.linalg.eig(scatter_matrix)

    eig_pairs = [(np.abs(eig_val[i]), eig_vec[:, i]) for i in range(n_features)]

    # sort eig_vec based on eig_val from highest to lowest

    eig_pairs = [((np.abs(eig_val[i])), eig_vec[:, i]) for i in range(len(eig_vec))]

    eig_pairs.sort(key=lambda x: x[0], reverse=True)

    # select the top k eig_vec

    feature = np.array([ele[1] for ele in eig_pairs[:k]])

    # get new data

    new_data = np.dot(norm_X, np.transpose(feature))

    return new_data

X_pca = pca(X, 1).real#.real取得复数的实部

print("X_pca:\n",X_pca)

X_pca:

 [[-1.38340578]

 [-2.22189802]

 [-3.6053038 ]

 [ 1.38340578]

 [ 2.22189802]

 [ 3.6053038 ]]

和刚刚结果绝对值相同, 正负相反, 但是和原数据的正负还是保持一致的, 感觉没有大问题(有时间对照包源码找下原因)

逆转换:

def pca(X, k): # k is the components you want

    # mean of each feature

    n_samples, n_features = X.shape

    mean = np.array([np.mean(X[:, i]) for i in range(n_features)])

    # normalization

    norm_X = X - mean

    # scatter matrix

    scatter_matrix = np.dot(np.transpose(norm_X), norm_X)

    # Calculate the eigenvectors and eigenvalues

    eig_val, eig_vec = np.linalg.eig(scatter_matrix)

    eig_pairs = [(np.abs(eig_val[i]), eig_vec[:, i]) for i in range(n_features)]

    # sort eig_vec based on eig_val from highest to lowest

    eig_pairs = [((np.abs(eig_val[i])), eig_vec[:, i]) for i in range(len(eig_vec))]

    eig_pairs.sort(key=lambda x: x[0], reverse=True)

    # select the top k eig_vec

    feature = np.array([ele[1] for ele in eig_pairs[:k]])

    # get new data

    new_data = np.dot(norm_X, np.transpose(feature))

    return new_data,feature,mean

# X_pca = pca(X, 1)#可行

X_pca,X_components,X_mean = pca(X, 1)

print("X_pca:\n",X_pca)

X_origin=np.dot(X_pca, X_components)+X_mean

print("X_origin:\n",X_origin)

X_pca:

 [[-1.38340578]

 [-2.22189802]

 [-3.6053038 ]

 [ 1.38340578]

 [ 2.22189802]

 [ 3.6053038 ]]

X_origin:

 [[-1.15997501 -0.75383654]

 [-1.86304424 -1.21074232]

 [-3.02301925 -1.96457886]

 [ 1.15997501  0.75383654]

 [ 1.86304424  1.21074232]

 [ 3.02301925  1.96457886]]

结果与调包相同, 基本没问题

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值