数据预处理(下)
PCA与SVD算法
这次主要是单独记录一下两种最常见的降维算法,PCA和SVD,也是实际应用在使用很广泛的两种降维算法,也属于数据预处理的一部分。本文会记录示例代码和理论部分的知识。
PCA算法理论推导
- 动机:给定的数据有时特征维度很高,但是有些特征维度之间相互关联,不是各自独立的,也就是说,这些维度并不
需要全部考虑进去。 - 举例:如下图所示
图中给定三个数据点,不难看出,虽然数据是二维的,但是反应数据分布情况的只有一个维度,如果做一下线性变换,旋转一下坐标轴,如第二张图所示,那么完全可以用一维坐标来表示这组数据,因为经过变换之后另外一个维度对于数据的区分度很低,完全可以舍弃。 - 目的:将原始数据做一个线性变换,要求经过变换后的数据可以用更少的维度来表示数据的分布情况。因为维度减少,必然有信息损失,还要要求这种损失尽可能地降低。
- 定量标准:说到现在,还都是一些定性的讨论,比如我们要达到用更少的维度来表示数据的分布情况,可是如何衡量表示数据分布的好坏呢?这里PCA的基本思路是使用方差最大化。
直观上我们可以看到,当数据在某些维度的方差大的时候,说明数据在这个维度上分布很广泛。反之,如果数据在某些维度方差小,说明数据在这个维度上都分布得很集中,没有什么区分度,换句话说,在这些方差小的维度上观察数据会发现,这些数据没有很大不同,全都长得差不多,那么我们认为这样的特征维度对于我们的分类或者回归任务是没有什么太大作用的,应该是要舍弃的。 公式推导
根据以上目标,开始进行理论推导。
一个数据点可以表示为一个向量,这个向量是定义在原有的一组正交基底上的。
x=⎡⎣⎢⎢⎢⎢x1x2...xd⎤⎦⎥⎥⎥⎥=x1e1+x2e2+...+xded
假设现在经过线性变换之后,找到了另外一组正交基 [w1w2...wd] ,在这组正交基下,数据的方差达到了最大,也就是说数据的分布最为分散了。那么我们可以得出,原有数据在这个新基底下的表示:
x=WWTx=(∑i=1dwiwti)x=(wT1x)w1+(wT2x)w2+...+(wTdx)wd
注意,这里利用了正交基底的性质 WWT=I
得出新坐标如下:
y=⎡⎣⎢⎢⎢⎢wT1xwT2x...wTdx⎤⎦⎥⎥⎥⎥
也就是说,一个数据点在新基底下的坐标可以由原来的数据点的坐标 x 和已知的新的正交基底通过上式计算出来。
现在已经知道如何计算新的坐标表示了,那么下一个问题就来了,就是这个新的正交基底怎么得到的呢?
如前所述,我们需要是的整个数据集在新的坐标系下方差达到最大,所以,我们待定一个新的正交基底,根据上面的表示公式可以把原有的数据点都变换为新的基底下的表示。
注意此时新的基底仍然是待定参数,并没有实际求解出来。
获得了原有数据在新坐标系下的表示后,使得这组新数据表示的方差求最大值,这样反解出基底,就可以拿到这组新的正交基底的具体数值了。
所有训练用的数据点用待定的新的基底表示为:
⎧⎩⎨⎪⎪⎪⎪⎪⎪⎪⎪y1=⎡⎣⎢⎢⎢⎢wT1x1wT2x1...wTdx1⎤⎦⎥⎥⎥⎥=WTx1,y2=⎡⎣⎢⎢⎢⎢wT1x2wT2x2...wTdx2⎤⎦⎥⎥⎥⎥=WTx2,...,yn=⎡⎣⎢⎢⎢⎢wT1xnwT2xn...wTdxn⎤⎦⎥⎥⎥⎥=WTxn⎫⎭⎬⎪⎪⎪⎪⎪⎪⎪⎪
这组变换后的新数据的方差为:
1n∑i=1n(WTxi−μ)2=1n∑i=1n(WTxi−WTx¯)2=1n∑i=1n(WT(xi−x¯))2=1n∑i=1nWT(xi−x¯)(xi−x¯)TW=WT(1n∑i=1n(xi−x¯)(xi−x¯)T)W=trace(WTCW)s.t.WTW=I
其中经过简单的线性代数变换,我们可以发现,上面的最后的那个公式就是化简后的新基底下数据的方差,其中未知的参数就是 W ,C 是原始数据的协方差矩阵。所以只要对其进行优化就可以了,由于这个问题是凸的,可以直接求导,然后令导数等于0,解出的 W 就是新的基底。
求导可等于0以得到下面的结果:
CW=λW
是不是很眼熟,这就是求特征值特征向量的公式。
于是乎,问题就简化成了求协方差矩阵 C 的特征值特征向量。
经过了看似很麻烦的数学推导,但是这个算法总结起来异常简单:在原始数据集上计算均值向量
x¯ - 计算原始数据集的协方差矩阵
计算协方差矩阵的特征值特征向量,选前k大的特征值,对应的特征向量就是新的基底,这些特征向量组合在一起就是变换矩阵 W ,这样原始数据就会被降到K维。
说明几点:协方差矩阵是一个实对称阵,而且是一个半正定的矩阵,n个数据点构成的协方差矩阵C是n*n的,它的秩最大就是n-1,因此降维可以最大降到n-1维。
为了衡量降维后损失了信息多少,可以用特征值的大小来衡量,特征值越大,说明对应的特征向量表示的信息越多,因此可以计算选择前k个大的特征值大小占所有特征值大小的比例来衡量信息的损失。
上图表示UCI数据集上的特征值大小的分布情况,可以很清楚的看出,前面几个特征值基本上就已经占据了树枝上的绝对多数,而后面大量特征值幅度均很小,完全可以舍弃,丢失的信息也不会很多。
SVD与PCA很类似,具体推导就省略了,只写出关键的部分:
优化目标:
类似的,具体算法为:
- 计算原始数据集的奇异值和左奇异向量 U=(μ1,μ2,...,μk) 。
新坐标的表示为: UTkX
SVD分解有一个好处,就是可以对任意矩阵进行分解,相比较而言,PCA使用特征值分解只适用于方阵,当然,协方差矩阵一定是方阵。但是考虑这样一种情况,如果给出的数据比较稀疏,则SVD具有优势,原因是,SVD可以直接对原始数据操作,而PCA还需要一步减去均值的操作,这样原本比较稀疏的数据计算出来的C将会变得不稀疏,无论是储存空间还是程序执行效率都会下降。
另外,还可以用SVD来求解PCA。
奇异值分解有一个很好的数学性质:
X
的左奇异向量是
所以,先求出原始数据的均值向量
x¯
,然后直接计算
[x1−x¯,x2−x¯,...,xn−x¯]
的左奇异向量,也就得出了
C
<script type="math/tex" id="MathJax-Element-920">C</script>的特征向量。
经过了繁琐的数学推导,我们脱离数学理一下思路,PCA和SVD其实都是在做这样一件事情,那就是用线性变换来降维,说到线性变换,就需要一个变换矩阵,上面废了这么大力气,其实就是在求这个变换矩阵,也就是新的基底,新的坐标系。
为什么说PCA和SVD是线性降维方法呢?不难看出,我们做了一系列数学推导,都是线性代数的东西,所有的推导都是线性模型,其实也有其他的方法,比如非线性降维,如ISOMAP等等图降维办法,后续会介绍。
最后说一下降维和特征选择有何不同,这其实是两个概念,这个问题也是在开组会的时候讨论辨析清楚的,降维是把原来的特征空间整个改变了,无论你用了线性方法还是非线性方法,特征空间已经和原来的空间不一样了。特征选择不同,原来的特征空间没变,我只是在若干个特征维度上选取有利于最后结果的几个维度。
代码实现
下面主要是贴上代码实现,分别是PCA和SVD的,应当来说这两个算法落地都非常简单,难度也不大。目前这种办法基本是属于工具性质的东西,直接调用sklearn的函数也是可以的。
def PCA(dataMat,k):
meanVals = np.mean(dataMat, 0)
meanRemove = dataMat - meanVals # 去均值
covMat = np.cov(meanRemove, rowvar=0) # 求协方差矩阵
print covMat.shape
eigVals, eigVects = np.linalg.eig(np.mat(covMat)) # 求协方差矩阵特征值与特征向量
eigValInd = np.argsort(eigVals)
eigValInd = eigValInd[:-k-1:-1] # 取出指定个数的前n大的特征值
redEigVects = eigVects[:, eigValInd]
return redEigVects
def SVD(dataMat,k):
U, s, V = np.linalg.svd(dataMat.T)
transferMat = U[:, :k]
return transferMat
两个函数返回的都是新的基底组成的变换矩阵。
PCA和SVD都可以看做是一种无监督的学习方法,学习到的就是一组新的正交基底构成的变换矩阵,这个变换矩阵可以对训练数据集直接使用来降维,也可以对同分布情况的测试数据集使用。
最后,给出一个链接,这上面讲解的PCA更加详细,可以更加深入地理解PCA。
参考链接
PCA数学原理