我是靠谱客的博主 开放流沙,最近开发中收集的这篇文章主要介绍【机器学习】PCA、SVD深入浅出与python代码,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

文章转自微信公众号:机器学习炼丹术

  • 笔记:陈亦新

我个人的理解:PCA本质上就是寻找数据的主成分。我们可以简单的打个比方,假设有一组高维数据。他的主成分方向就是用一个线性回归拟合这些高维数据的方向。用最小二乘的逻辑拟合的。其他的主成分都是与最大主成分正交的。


那么我们如何得到这些包含主成分方向呢?

通过计算数据矩阵的协方差矩阵,然后得到协方差矩阵的特征值和特征向量,选择特征值最大的k个特征对应的特征向量组成的矩阵就可以了。这个矩阵就可以将原始m维度的特征转换成k维度。


那么我们如何得到数据的特征向量呢?

一般有两种方法:

  1. 特征值分解协方差矩阵

  2. 奇异值分解协方差矩阵。

所以PCA算法有两种实现,分别是基于特征值分解方差矩阵实现PCA、基于SVD分解的协方差矩阵PCA算法。

协方差矩阵和散度矩阵

样本均值:

样本方差:

样本X和样本Y(X和Y是两个变量)的协方差:

从上面公式可以得到以下结论:

  • 协方差是在两个变量间计算的,方差可以看成协方差的特征情况

  • 方差和协方差除以了n-1,这是得到方差和协方差的无偏估计。

协方差大于0,X和Y为正相关关系,小于0就是负相关,等于0就是相互独立。

当现在有N个变量,我们要计算这n个变量的彼此两两的协方差的时候,就构成了协方差矩阵。对于三个变量XYZ:

c0d3ffb3457957659c04c0613e647251.png
image.png

现在我们来看散度矩阵的定义。

the scatter matrix is computed by  the following equation:

需要注意的是,散度矩阵和协方差矩阵其实就是倍数关系(n-1)倍。散度矩阵的写法是矩阵的写法,和协方差矩阵公式其实等价。

  • 公式中的n是样本数量

  • 对于每一个样本,我们可以假设每一个样本都包含n个特征,也就是每一个样本都是m维度数据。

  • 所以最后可以得到一个mxm的矩阵,分别表示每一个特征和其他的特征的协方差(散度)

  • 写成矩阵的形式,假设是mxn的张量,那么散度矩阵可以写成

散度矩阵和协方差矩阵的特征值和特征向量是一样的。

特征值分解矩阵原理

特征值分解和奇异值分解在机器学习中都是很常见的矩阵分解算法。两者有着很紧密的关系,目的都是提取出矩阵的最重要的特征。

如果一个向量v是矩阵A的特征向量,那么一定可以表示成下面的形式:

其中是特征向量v对应的特征值,一个矩阵的特征向量彼此正交。


这时候问题来了:为什么一个向量和矩阵相乘的结果和一个数字相乘的效果一样呢?

因为矩阵A和向量b相乘,就是对向量v进行了一次线性的变换,旋转、拉伸等等。如果改变换等价于一个常熟的倍数变换,那么就以位置,我们求取特征向量的时候,就是为了求矩阵A可以使得那些哪些向量只发生伸缩变换,不发生旋转变换


我们来看特征值和特征向量的几何意义

参考资料:机器学习中SVD总结 (qq.com)

一个矩阵其实就是一次线性比那换,因为矩阵乘以一个向量后得到的向量,就相当于是将这个向量进行了线性变换,比方说下面这个矩阵

b27ce40097a5f082319e65a041362ff3.png
image.png

自己可以尝试一下,其实就是让x方向变成原来的3倍,y方向是原来的1倍:

c881c07be86cb11a457f87f7fff81c22.png
image.png

所以是这个样子的:

273ad8719900c0423be7a70d09b6950a.png
image.png

同理,这样的矩阵是一个拉伸变换:

51ca28d726ea67d80a22ae6f743c60de.png
image.png
76f9698fe66a68bb2dba082cb6c85732.png
image.png

现在我们知道了,矩阵对于一个向量来说,就是一种线性变换。特征值分解就是将矩阵A分解成下面的样子:

  • Q是矩阵A的特征向量组成的矩阵,是一个对角矩阵,对角线上的元素就是特征值。分解的这个矩阵是一个对角矩阵,里面的特征值是从大到小排列的。

  • 上面公式怎么来的呢?其实就是从特征值的定义得到的。

展示的是单个特征向量的变化。假设矩阵A是mxm的方针。那么v就是一个mx1的某一个特征向量。如果我们对所有的m个特征向量都做这个运算,那么就可以写成:

这里需要反过来,自己举一个例子就可以发现,需要反过来。

然后我们把左边的V变成右边的可逆形式就可以了。

奇异值分解

特征值分解只能针对方针,如果A是一个非方阵,尤其是在PCA当中,样本的特征数量和样本数量一般都是不相同的。这时候就无法使用特征值分解的方法来计算特征向量。

  • SVD,singular value decomposition


定义

对于任意矩阵A总是存在一个奇异值分解:

假设A是一个mn的矩阵,那么U是一个mm的仿真,U的正交向量(特征向量)被称为左奇异向量,是一个mn的矩阵,是一个对角矩阵,对角线上的元素称为奇异值。是一个nn的矩阵,里面的正交向量被称为右奇异向量。

需要注意的是:

  • 与特征值分解类似,U和V都是正交矩阵,也就是理解为特征向量拼成的矩阵;


那么我们如何计算奇异值和奇异向量呢?还得回到特征向量的定义当中。

这里的v就是右奇异向量,也就是说就是

更有趣的是:

这里的u就是左奇异向量,也就是说就是


为什么有这样的效果呢?

这里单位矩阵,因为U是正交矩阵。

所以上证明了的特征向量,就是我们的V,矩阵V就是ATA的特征向量,那么就是矩阵V的特征值。从上公式中可以看到,奇异值就是特征值的0.5次方。


总结:现在我们已经知道用奇异值分解SVD来处理任何的矩阵了。也就是说,任何的矩阵都可以被分解的形式。

那么SVD降维,就是选择最大的几个奇异值和奇异向量来描述数据就可以了。因为奇异值的下降速度非常快,可能最大的1%的奇异值就已经占据了全部奇异值之和的99%以上

PCA

现在我们了解了特征值分解和奇异值分解。

【基于特征值分解协方差矩阵实现PCA】

  1. 去平均值,每一个特征都要预处理,变成0均值分布

  2. 计算协方差矩阵或者散度矩阵,就是

  3. 用特征值分解求协方差矩阵的特征值和特征向量

  4. 选择最大的k个特征值的特征向量,组成一个特征向量矩阵P,这个矩阵的形状为mxk的,m是原来样本特征维度,也是协方差矩阵(方阵)的维度。

  5. 每一个数据都包含m个特征,堪称是1xm的向量,与mxk的特征向量做乘法就可以得到1xk的压缩特征。

本质就是选择k中加权方案,每一个方案都是对原来m个特征进行线性加权组合,唯一的限制就是加权方案彼此正交。

【基于SVD分解的协方差矩阵实现PCA】 其实流程和上面是一样的,计算协方差矩阵,通过SVD计算特征值和特征向量(奇异向量)

区别在于,PCA在特征值分解中,需要计算出协方差矩阵的k个最大特征向量。计算协方差矩阵的时候其实计算量非常大,比方说有上万个数据,每个数据有上万个特征。假设都是1w样本和1w特征,那么kxn与nxk两个矩阵结果得到一个10000x10000的协方差矩阵,这个矩阵的每一个元素都需要经过10000次乘法运算,所以需要1万亿次的计算。

SVD来做分解的时候,SVD的实现算法有一些可以不求出协方差矩阵,在不求的情况下,也可以求出我们的左奇异矩阵U。实际上scikit-learn的PCA算法背后就是用SVD实现的,而不是特征值分解。


左右奇异矩阵都可以作为降维的矩阵使用。两者分别降维样本矩阵的两个维度,一个是特征,也就是我们常用的左奇异矩阵;另一个是降低样本数量,是用的右奇异矩阵。

python代码

用特征值分解的方法,把6个样本2个特征转化为1个特征:

##Python实现PCA
import numpy as np
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.sort(reverse=True)
    # select the top k eig_vec
    feature=np.array([ele[1] for ele in eig_pairs[:k]])
    #get new data
    data=np.dot(norm_X,np.transpose(feature))
    return data

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

print(pca(X,1))

结果:

9c570a4a524992b1e395611d79f9752f.png

用scikit-learn的方法:

from sklearn.decomposition import PCA
import numpy as np
X = np.array([[-1,1],[-2,-1],[-3,-2], [1, 1], [2, 1], [3, 2]])
pca = PCA(n_components=1)
pca.fit(X)
print(pca.transform(X))

结果:

c73b324b374490126096a707b628933c.png
 
 

f6ba93b0b6a85a6578e7fed33ce08fd2.jpeg

 
 
 
 
 
 
 
 
往期精彩回顾




适合初学者入门人工智能的路线及资料下载(图文+视频)机器学习入门系列下载机器学习及深度学习笔记等资料打印《统计学习方法》的代码复现专辑机器学习交流qq群955171419,加入微信群请扫码

最后

以上就是开放流沙为你收集整理的【机器学习】PCA、SVD深入浅出与python代码的全部内容,希望文章能够帮你解决【机器学习】PCA、SVD深入浅出与python代码所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(36)

评论列表共有 0 条评论

立即
投稿
返回
顶部