2

详解主成分分析PCA与奇异值分解SVD-降维后的矩阵components_ & inverse_transform...

 1 year ago
source link: https://blog.51cto.com/u_15767241/5854647
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

详解主成分分析PCA与奇异值分解SVD-降维后的矩阵components_ & inverse_transform【菜菜的sklearn课堂笔记】

推荐 原创

视频作者:[菜菜TsaiTsai]
链接:[【技术干货】菜菜的机器学习sklearn【全85集】Python进阶_哔哩哔哩_bilibili]

V(k,n)这个矩阵保存在.components_这个属性当中
我们之前谈到过PCA与特征选择的区别,即特征选择后的特征矩阵是可解读的,而PCA降维后的特征矩阵式不可解读的:PCA是将已存在的特征进行压缩,降维完毕后的特征不是原本的特征矩阵中的任何一个特征,而是通过某些方式组合起来的新特征。通常来说,在新的特征矩阵生成之前,我们无法知晓PCA都建立了怎样的新特征向量,新特征矩阵生成之后也不具有可读性,我们无法判断新特征矩阵的特征是从原数据中的什么特征组合而来,新特征虽然带有原始数据的信息,却已经不是原数据上代表着的含义了。
但是其实,在矩阵分解时,PCA是有目标的:在原有特征的基础上,找出能够让信息尽量聚集的新特征向量。在sklearn使用的PCA和SVD联合的降维方法中,这些新特征向量组成的新特征空间其实就是V(k,n)。当V(k,n)是数字时,我们无法判断V(k,n)和原有的特征究竟有着怎样千丝万缕的数学联系。但是,如果原特征矩阵是图像,V(k,n)这个空间矩阵也可以被可视化的话,我们就可以通过两张图来比较,就可以看出新特征空间究竟从原始数据里提取了什么重要的信息

我们以人脸识别中属性components_为例

from sklearn.datasets import fetch_lfw_people
from sklearn.decomposition import PCA
import matplotlib.pyplot as plt
import numpy as np

faces = fetch_lfw_people(min_faces_per_person=60) # 实例化
# min_faces_per_person:在数据集中每个人取出n张脸图

print(faces.DESCR) # 需要的话自己看吧

faces.data.shape
# 每一行是样本,即1348个样本
# 列式样本相关的所有特征,即2914个特征
# 因此,可视化这一部分没有意义
---
(1348, 2914)

faces.images.shape # 注意是三维的
# 严格来说,这个才是图像的特征矩阵
# 1348是矩阵中图像的个数
# 62是每个图像的特征矩阵的行,行上有62个像素
# 42是每个图像的特征矩阵的列,列上有47个像素
# 之前的2914=62*47,一张图就要有一行一列,可以看做一个表
# 因此我们可以对62*47这一部分进行可视化
---
(1348, 62, 47)

X = faces.data

# 之前的plt.figure是无法画多个图的
fig, axes = plt.subplots(4,5 # 子图4行5列。现在直接执行会给4*5=20个框,其他什么也没有
                         # 4,5表示要画20个图,在这里也就是20张脸,可以写其他数
                       ,figsize=(8,4) # 画布的尺寸和比例和大小,8代表行,4代表列
                         # figsize的对象是figure不是某一个subplot
                       ,subplot_kw={"xticks":[],"yticks":[]} # 不显示坐标轴
                        )
详解主成分分析PCA与奇异值分解SVD-降维后的矩阵components_ & inverse_transform【菜菜的sklearn课堂笔记】_python
fig # 生成的一张纸
详解主成分分析PCA与奇异值分解SVD-降维后的矩阵components_ & inverse_transform【菜菜的sklearn课堂笔记】_机器学习_02
axes # 4行5列,matplotlib的对象
# axes中的一个对象对应fig中的一个空格
---
array([[<matplotlib.axes._subplots.AxesSubplot object at 0x0000011CA315B198>,
        <matplotlib.axes._subplots.AxesSubplot object at 0x0000011CA52DF2B0>,
        <matplotlib.axes._subplots.AxesSubplot object at 0x0000011CA530D828>,……
# 4*5的array,里面都是matplotlib对象

axes.shape
---
(4, 5)

axes[0,0] # 指定那个对象和一般的矩阵一样

axes[0,0].imshow(faces.images[0,:,:])
# 生成一个更新过的matplotlib对象
# 我们只是改变了axes对象,在这里执行完这个cell显示图像
# 只有再次看fig画布才看看到效果
# imshow要求的数据格式必须是一个(m,n)格式的矩阵,即每个数据都是一张单独的图,我们需要遍历的是faces.images,其结构是(1277, 62, 47)
fig
详解主成分分析PCA与奇异值分解SVD-降维后的矩阵components_ & inverse_transform【菜菜的sklearn课堂笔记】_python_03

我们要花4×5=204\times 5=204×5=20个图,二维结构,可以有两种循环方式,一种是使用索引,循环一次同时生成一列上的三个图;另一种是把数据拉成一维,循环一次只生成一个图。这里我们选择后者

[*enumerate(axes.flat)]
---
[(0, <matplotlib.axes._subplots.AxesSubplot at 0x11ca315b198>),
 (1, <matplotlib.axes._subplots.AxesSubplot at 0x11ca52df2b0>),
 (2, <matplotlib.axes._subplots.AxesSubplot at 0x11ca530d828>),
 (3, <matplotlib.axes._subplots.AxesSubplot at 0x11ca5332da0>),
# flat降维成一维
# enumerate每个对象带序号构成一个元组,因为是惰性对象,所以在列表中可以用*打开

填充所有子图

for i, ax in enumerate(axes.flat):
    ax.imshow(faces.images[i,:,:],cmap='gray') # 选择色彩的模式,原本显示绿色,设置显示黑白

fig

降维,并获取components_

pca = PCA(150).fit(X) # X = faces.data,注意faces.data.shape为(1348, 2914)
V = pca.components_ # 是V^T而不是V
V.shape
---
(150, 2914)

V[0].shape # 这一行的shape,意义不大
---
(2914,)

V[0].reshape(62,47).shape # 这里实际上是被选中的降维所用的特征向量进行reshape
---
(62, 47)

fig, axes = plt.subplots(5,10,figsize=(8,4),subplot_kw = {"xticks":[],"yticks":[]})
for i,ax in enumerate(axes.flat):
    ax.imshow(V[i,:].reshape(62,47),cmap='gray')
# 这里对V进行可视化,显然画的不是图片,而是特征向量
# 个人理解,这里的V是150*2914,150个特征向量也就是150个最重要的点
# X*V,也就是通过X对V这150个特征组成的图像进行加权得到降维后的图像
# 越靠前的V越重要,越靠后的区分度越小
# 前几个特征也就是这个前几个图像主要关注了五官的位置,光照等
详解主成分分析PCA与奇异值分解SVD-降维后的矩阵components_ & inverse_transform【菜菜的sklearn课堂笔记】_算法_04

可以看出,比起降维前的数据,新特征空间可视化后的人脸非常模糊,这是因为原始数据还没有被映射到特征空间中。但是可以看出,整体比较亮的图片,获取的信息较多,整体比较暗的图片,却只能看见黑漆漆的一块。在比较亮的图片中,眼睛,鼻子,嘴巴,都相对清晰,脸的轮廓,头发之类的比较模糊。
这说明,新特征空间里的特征向量们,大部分是"五官"和"亮度"相关的向量,所以新特征向量上的信息肯定大部分是由原数据中和"五官"和"亮度"相关的特征中提取出来的。到这里,我们通过可视化新特征空间V,解释了一部分降维后的特征:虽然显示出来的数字看着不知所云,但画出来的图表示,这些特征是和”五官“以及”亮度“有关的。这也再次证明了,PCA能够将原始数据集中重要的数据进行聚集。

一片不错的文章可以看一下
作者:[雪球球]
链接: 图像处理之基础—矩阵和特征向量的 几何意义 - 雪球球 - 博客园 (cnblogs.com)

详解主成分分析PCA与奇异值分解SVD-降维后的矩阵components_ & inverse_transform【菜菜的sklearn课堂笔记】_python_05

这里关于白化其实在sklearn里就是一个参数

PCA(
    ['n_components=None', 'copy=True', 'whiten=False', "svd_solver='auto'", 'tol=0.0', "iterated_power='auto'", 'random_state=None'],
)
# whiten:是否PCA后进行白化

个人理解,我们PCA是求的Xdr=X⋅VX_{dr}=X \cdot VXdr​=X⋅V,其中VVV是特征向量组成的矩阵,白化PCA就是Xw=X⋅V⋅Λ−12X_{w}= X \cdot V \cdot \Lambda^{- \frac{1}{2}}Xw​=X⋅V⋅Λ−21​,这里Λ\LambdaΛ就是协方差矩阵SSS的特征值

Σw=1mXwTXw=1mΛ−12VTXT⋅XVΛ−12=Λ−12VT⋅1mXTX⋅VΛ−12=Λ−12VTSVΛ−12=Λ−12VT⋅VΛVT⋅VΛ−12=I\begin{aligned} \Sigma_{w}&=\frac{1}{m}X_{w}^{T}X_{w}\\ &=\frac{1}{m}\Lambda^{- \frac{1}{2}}V^{T}X^{T} \cdot XV\Lambda^{- \frac{1}{2}}\\ &=\Lambda^{- \frac{1}{2}}V^{T}\cdot \frac{1}{m}X^{T}X \cdot V \Lambda^{- \frac{1}{2}}\\ &=\Lambda^{- \frac{1}{2}} V^{T}S V \Lambda^{- \frac{1}{2}}\\ &=\Lambda^{- \frac{1}{2}}V^{T}\cdot V \Lambda V^{T}\cdot V\Lambda^{- \frac{1}{2}}\\ &=\text{I} \end{aligned} Σw​​=m1​XwT​Xw​=m1​Λ−21​VTXT⋅XVΛ−21​=Λ−21​VT⋅m1​XTX⋅VΛ−21​=Λ−21​VTSVΛ−21​=Λ−21​VT⋅VΛVT⋅VΛ−21​=I​

因此我们说数据在经过PCA白化以后,其协方差矩阵是一个单位矩阵,各维度不线性相关,且每个维度方差都是1

各维度不相关不需要白化,只进行PCA也能达到,因为新的特征向量本身就是互相垂直的

详解主成分分析PCA与奇异值分解SVD-降维后的矩阵components_ & inverse_transform【菜菜的sklearn课堂笔记】_python_06

作者: 王亮
链接: 白化变换:PCA白化、ZCA白化 - 知乎 (zhihu.com)

这里我们暂时不关心ZCA(感觉ZCA的图也不太对)

inverse_transform

在特征工程课中,我们学到了接口inverse_transform,可以将我们归一化,标准化,甚至做过哑变量的特征矩阵还原回原始数据中的特征矩阵,这几乎在向我们暗示,任何有inverse_transform这个接口的过程都是可逆的。PCA应该也是如此。在sklearn中,我们通过让原特征矩阵X右乘新特征空间矩阵V((k,n))V_{((k,n))}V((k,n))​来生成新特征矩阵XdrX_{dr}Xdr​,那理论上来说,让新特征矩阵XdrX_{dr}Xdr​右乘V(k,n)的逆矩阵V((k,n))−1V^{-1}_{((k,n))}V((k,n))−1​,就可以将新特征矩阵XdrX_{dr}Xdr​还原为X。

用上面人脸识别看PCA降维后的信息保存量

from sklearn.datasets import fetch_lfw_people
from sklearn.decomposition import PCA
import matplotlib.pyplot as plt
import numpy as np

faces = fetch_lfw_people(min_faces_per_person=60)
X = faces.data
X.shape
---
(1348, 2914)

pca = PCA(150)
X_dr = pca.fit_transform(X)
X_dr.shape
---
(1348, 150)

X_inverse = pca.inverse_transform(X_dr)
X_inverse.shape
# 期待X_inverse和原数据有相同的结构,如果相同,我们就说inverse_transform实现了降维过程的逆转
# 维度相同,即使inverse_transform将降维后的数据映射回原数据所在的维度空间中,但信息已经损失了
---
(1348, 2914)

fig, ax = plt.subplots(2,10,figsize=(10,2.5)
                     ,subplot_kw={'xticks':[],'yticks':[]}
                     )
for i in range(10):
    ax[0,i].imshow(faces.images[i,:,:],cmap='binary_r')
    ax[1,i].imshow(X_inverse[i].reshape(62,47),cmap='binary_r')
fig
# 第一行是原数据,第二行是inverse_transform后返回的数据
---
详解主成分分析PCA与奇异值分解SVD-降维后的矩阵components_ & inverse_transform【菜菜的sklearn课堂笔记】_算法_07

可以明显看出,这两组数据可视化后,由降维后再通过inverse_transform转换回原维度的数据画出的图像和原数据画的图像大致相似,但原数据的图像明显更加清晰。这说明,inverse_transform并没有实现数据的完全逆转。这是因为,在降维的时候,部分信息已经被舍弃了,XdrX_{dr}Xdr​中往往不会包含原数据100%的信息,所以在逆转的时候,即便维度升高,原数据中已经被舍弃的信息也不可能再回来了。所以,降维不是完全可逆的。
inverse_transform的功能,是基于XdrX_{dr}Xdr​中的数据进行升维,将数据重新映射到原数据所在的特征空间中,而并非恢复所有原有的数据。但同时,我们也可以看出,降维到300以后的数据,的确保留了原数据的大部分信息,所以图像看起来,才会和原数据高度相似,只是稍稍模糊罢了。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK