我个人的理解:PCA本质上就是寻找数据的主成分。我们可以简单的打个比方,假设有一组高维数据。他的主成分方向就是用一个线性回归拟合这些高维数据的方向。用最小二乘的逻辑拟合的。其他的主成分都是与最大主成分正交的。
那么我们如何得到这些包含主成分方向呢?
通过计算数据矩阵的协方差矩阵,然后得到协方差矩阵的特征值和特征向量,选择特征值最大的k个特征对应的特征向量组成的矩阵就可以了。这个矩阵就可以将原始m维度的特征转换成k维度。
那么我们如何得到数据的特征向量呢?
一般有两种方法:
所以PCA算法有两种实现,分别是基于特征值分解方差矩阵实现PCA、基于SVD分解的协方差矩阵PCA算法。
协方差矩阵和散度矩阵 样本均值:
样本方差:
样本X和样本Y(X和Y是两个变量)的协方差:
从上面公式可以得到以下结论:
协方差是在两个变量间计算的,方差可以看成协方差 的特征情况 方差和协方差除以了n-1,这是得到方差和协方差的无偏估计。 协方差大于0,X和Y为正相关关系,小于0就是负相关,等于0就是相互独立。
当现在有N个变量,我们要计算这n个变量的彼此两两的协方差的时候,就构成了协方差矩阵。对于三个变量XYZ:
image.png 现在我们来看散度矩阵的定义。
❝ the scatter matrix is computed by the following equation:
需要注意的是,散度矩阵和协方差矩阵其实就是倍数关系(n-1)倍。散度矩阵的写法是矩阵的写法,和协方差矩阵公式其实等价。
对于每一个样本 ,我们可以假设每一个样本都包含n个特征,也就是每一个样本都是m维度数据。 所以最后可以得到一个mxm的矩阵,分别表示每一个特征和其他的特征的协方差(散度) 写成矩阵的形式,假设
是mxn的张量,那么散度矩阵可以写成 散度矩阵和协方差矩阵的特征值和特征向量是一样的。
特征值分解矩阵原理 特征值分解和奇异值分解在机器学习中都是很常见的矩阵分解算法。两者有着很紧密的关系,目的都是提取出矩阵的最重要的特征。
如果一个向量v是矩阵A的特征向量,那么一定可以表示成下面的形式:
其中 是特征向量v对应的特征值,一个矩阵的特征向量彼此正交。
这时候问题来了:为什么一个向量和矩阵相乘的结果和一个数字相乘的效果一样呢?
因为矩阵A和向量b相乘,就是对向量v进行了一次线性的变换,旋转、拉伸等等。如果改变换等价于一个常熟的倍数变换,那么就以位置,我们求取特征向量的时候,就是为了求矩阵A可以使得那些哪些向量只发生伸缩变换,不发生旋转变换 。
我们来看特征值和特征向量的几何意义
参考资料:机器学习中SVD总结 (qq.com)
一个矩阵其实就是一次线性比那换,因为矩阵乘以一个向量后得到的向量,就相当于是将这个向量进行了线性变换,比方说下面这个矩阵
image.png 自己可以尝试一下,其实就是让x方向变成原来的3倍,y方向是原来的1倍:
image.png 所以是这个样子的:
image.png 同理,这样的矩阵是一个拉伸变换:
image.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】
选择最大的k个特征值的特征向量,组成一个特征向量矩阵P ,这个矩阵的形状为mxk的,m是原来样本特征维度,也是协方差矩阵(方阵)的维度。 每一个数据都包含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 npdef 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 ))
结果:
用scikit-learn的方法:
from sklearn.decomposition import PCAimport 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))
结果: