PCA 简介
主成分分析(PCA)是最流行的降维算法,通过把数据从高维映射到低维来降低特征维度,同时保留尽可能多的信息。
在进行图像识别以及高维度数据降维处理中有很强的应用性,算法主要通过计算,选择特征值较大的特征向量来对原始数据进行基变换,不仅可以去除无用的噪声,还能减少计算量;广泛应用于降维、有损数据压缩、特征提取、数据可视化等领域。
三个数学概念
方差:衡量变量的离散程度。
方差
协方差:衡量两个变量的相关度,协方差为正时说明 X 和 Y 是正相关关系,协方差为负时 X 和 Y 是负相关关系,协方差为 0 时 X 和 Y 相互独立。
协方差
由于只能使用样本均值代替总体均值,所以分母除以 m-1,才是总体方差/协方差的无偏估计。其实,数据集样本量大的话,除以 m-1 和除以 m 区别不大。
协方差矩阵:协方差矩阵是包含与多个变量相关的方差和协方差的方阵。矩阵的对角元素为变量的方差,而非对角元素为所有变量对之间的协方差。
协方差矩阵
PCA 降维原理
以二维降一维为例:
PCA 降维的本质是,尽量保证数据在空间中的相对位置不变,通过旋转坐标系,换一个在某些维度能表达更多数据信息的坐标系去刻画数据。如上图所示,在新的坐标系下,主元2对应的维度,对刻画数据不起任何作用,可以直接把这个维度去掉,达到降维的目的。
有损降维
降维后,如果数据的相对位置完全不变,就是无损降维;如果数据的相对位置稍稍改变,就是有损降维。
降维的数学描述
坐标系变换的数学语言描述是基变换,坐标系对应的基为一组两两正交的单位向量。
以二维数据为例,下面是一个坐标系变换(基变换)的例子:
基变换
旋转坐标系到什么时候为止呢?
用数学语言表述:将一组 N 维向量降为 K 维,PCA 的做法是选择 K 个单位正交基,使得原始数据变换到这组基上后,变量之间的协方差都为 0,变量自身的方差尽可能大。
为什么要变量的方差尽可能的大?
方差越大,说明数据越分散,包含的信息量越多;方差越小,说明数据越紧密,越难区分。甚至方差小到一定程度,数据会重叠消失。
为什么要变量间的协方差都为 0?
协方差表示两个变量的相关性,相关性意味着两个变量不完全独立,必然存在重复表示的信息。而协方差为 0,表示两变量相互独立,表示的信息最大。
去均值化:让每个变量都减去自己的均值。
简化书写
去均值化的目的是简化协方差的表达,最终目的是简化协方差矩阵的表达。
假设我们只有 a 和 b 两个变量,将它们按行组成矩阵 X:
则:
协方差矩阵的计算
可知,就是矩阵 X 的协方差矩阵。
设 X 是原始数据,Y 是对 X 做基变换后的数据:
XY关系
Y 的协方差矩阵为:
Y的协方差矩阵
上式表达的其实是 Y 的协方差矩阵和 X 的协方差矩阵之间的关系。我们现在的目标就是:寻找一个矩阵 P,使得 D 是一个对角阵。所以 C 对应特征值最大的前 K 个特征向量就是我们要找的基。(这中间涉及到一点线性代数的知识,C 是一个对称阵,要让 D 对角化,求 C 的特征值和特征向量即可,用 C 的特征向量组成 P,得到的 D 就是对角阵,且对角线上的元素就是 C 的特征值。) PCA 降维的流程: 流程
SVD(奇异值分解)
SVDPCA 与 SVD 的奇异向量的压缩效果相同。至于是与左奇异向量压缩效果相同,还是与右奇异向量压缩效果相同,取决于你的原始矩阵是用行表示样本还是用列表示样本。如果用列表示样本,行表示样本维度,那么PCA 就与 SVD 的右奇异向量的压缩效果相同。反之,与左奇异向量的压缩效果相同。
由于 SVD 有更高效的方法求解,所以实际中经常会使用 SVD 求解 PCA,比如 sklearn 就是这样做的。
注意 SVD 本身与 PCA 的原理无关!
代码实操
导入 python sklearn.decomposition 下的 PCA 包。
包内:
fit_transform(X):用 X 来训练 PCA 模型,同时返回降维后的数据。
inverse_transform(newData):将降维后的数据转换为原始维度数据,可能和原始数据有些许差别。
import numpy as np
import matplotlib.pyplot as plt
from sklearn.decomposition import PCA
# 原始数据
X = np.array([[-1, -1], [-2, -1], [-3, -2], [1, 1], [2, 1], [3, 2]]);
# pca降维
pca = PCA(n_components = 1)
X1 = pca.fit_transform(X)
Y = pca.inverse_transform(X1)
print('原始数据:')
print(X)
print('降维后的数据:')
print(X1)
print('还原的数据:')
print(Y)
# 绘制散点图,可视化数据
fig = plt.figure()
ax1 = fig.add_subplot(121)
plt.xlabel('X')
plt.ylabel('Y')
ax1.scatter(X[:,0],X[:,1],c='r',marker='o')
# 绘制还原后的数据
ax2 = fig.add_subplot(122)
plt.xlabel('X')
ax2.scatter(Y[:,0],Y[:,1],c='b',marker='x')
plt.show()
运行结果:
运行结果
参考文献:
https://zhuanlan.zhihu.com/p/77151308
https://www.zhihu.com/question/41120789/answer/481966094
网友评论