数据降维
数据对于算法工程师来说可以说是无限复杂的,而这个复杂我们是不可能预估的,聪明而又懒惰嗯数据科学家发明一种方法叫做降维,不管你有多少维,维就要处理20维,所以这就是数据降维的由来,本文会介绍一种非常普通且好使的数据降维的方法–PCA
数据降维是机器学习下比较热门的一个话题,在数据挖掘的领域我们尝试使用一组特征来描述我们的主体,但是如何具体的描述一个主体呢?需要多少维度呢? 例如我们想要描述一个人,除了年龄、性别是不是还有血压温度、好人坏人、脾气好坏等等。简直就是枚举不完,如果我们无脑的罗列,那这些特征是不是就太多了,用1w维描述一个人吗? 好吧,这个我们也不知道,但是有一点我们是知道的,就是太多了,这里可能对于某些人来说没有什么用,例如对于医疗大数据来说,他们更关心血压、体温。对于性格、交际可能不需要特别了解。那怎么办呢?这个就是本文要说的,我们要降低维度,保留下来我们更加关心的维度,丢掉一些次要信息。当然如果你是一个专家,你可以通过特征选择来解决这个问题,如果不行,那么就需要本文的方法了。
PCA
中文名字叫做主成分分析算法,非常直白,就是把主要的成分提取出来,然后去除相关性[^1]的方法。它通过线性变换将原始特征映射到其他维度中。降低维度说明的是表示用一个近似的向量表示元素数据。
y=Wx
从上面的公式中能看出,x是原始数据,y是投影以后的向量,那么W如何来求呢?我们称这个W为投影矩阵,如果W知道了,那么我们这个算法就讲完了,嗯 太好了了,思路非常清晰。我们先来无脑的思考一个问题,我们有n个d维向量x,我们想把d组向量压缩一个向量x0,如何做比较合适呢?如果使用均方误差作为衡量标准。
L(x0)=i=0∑n∣∣x−x0∣∣2
显然,这个问题的最优解是不是当x每组取均值就可以让上面这个损失最小。当然本着科学的理念我们还是要证明的。就是求梯度为0的状态被。
∇L(x0)=2(x0−x)=0
求解上面的方程,可以得出上面提到的结论。
当然这个太过于简单,我会表示成如下形式:
m=n1i=1∑nxi
x=m+aie
ai是标量,e是单位向量。这个时候的误差函数为:
L(a,e)=i=1∑n∣∣m+aie−xi∣∣2
求损失函数的最小值,对ai求导,另整个偏导数为0
2eT(m+aie−xi)=0
aieTe=eT(xi−m)
因为eTe=1,所以
ai=eT(xi−m)
上面这个公式表达的含义是,样本均值和样本的方差的差对向量eT做投影。现在就会有另一个问题eT如何来确认?下面我们来引入一个散布矩阵[^2].我们稍后会用到。
S=i=1∑n(xi−m)(xi−m)T
不难发现,散布矩阵实际上是协方差矩阵的n倍。协方差矩阵定义如下
Σ=n1i=1∑n(xi−m)(xi−m)T
好的,我们言归正传,将上面求的的ai带入下面的目标函数,可以得到关于e的变量。
L(e)=i=1∑n(aie+m−xi)T(aie+m−xi)
=−eTSe+i=1∑n(m−xi)T(m−xi)
这里的S就是上面提到的散布矩阵哦。其中过程大家可以动手练练。
上面这公式我们发现,后半部分是和e无关的,也就是我们可以当成常数了,那么我们将关注点放到e上,e是单位向量,隐含条件就是eTe=1,那么上面这个公式就能引入拉格朗日函数变成一个优化问题。
L(e,λ)=−eTSe+λ(eTe−1)
求导并且等于0就能得到。
−2Se+2λe=0Se=λe
很明显,等式两边都有e,且结果是相等的,那么λ是散布矩阵S的特征值。e是特征向量,再一次转化为矩阵的特征值和特征向量的问题。矩阵S是半正定的[散布矩阵],因此一定是可以对角化的,并且所有特征值非负,对于任意的非0向量x,有
xTSx=xT(i=1∑n(m−xi)T(m−xi))x
=i=1∑n(xT(m−xi)T)(xT(m−xi))>=0
我们这里需要最大化‘e^Te‘,上面已经提到过了,将Se=λe两边同时乘以一个eT,会有如下公式
eTSe=λeeT=λ
当λ为散布矩阵的最大特征值的时候,‘e^TSe‘具有最大值,目标函数具有最小值。而λ是散布矩阵的特征值,也就是我们仅仅需要对散布矩阵进行特征值和特征向量分解,然后按照我们的需求和从大到小的顺序求我们想要的维度即可。
算法流程
计算样本集合的均值向量,将所有的向量减去均值向量,这个操作成为白化
计算样本协方差矩阵
对协方差矩阵进行特征值分解,得到所有的特征值和特征向量
将特征值从大到小排序,保留最大的一部分特征值对应的特征向量,以他们为行,形成投影矩阵。
降维过程
将样本减去均值向量
左乘投影矩阵,得到降维后的矩阵
数据重构
数据重构根据投影后的数据重构原始向量,于向量投影的作用相反
输入向量左乘以投影矩阵
加上均值向量就可以得到重构后的矩阵。
代码实例
行万里路,不如来段代码,咱们看看代码是如何实现这一个过程的,当然咱们生成环境中是有很多开源的控价来实现这一个过程的。
# coding=utf-8
import numpy as np
data = np.array([[2.5,2.4],
[0.5, 0.7],
[2.2, 2.9],
[1.9, 2.2],
[3.1, 3.0],
[2.3, 2.7],
[2, 1.6],
[1, 1.1],
[1.5, 1.6],
[1.1, 0.9]])
print "原始数据:"
print data
def zeroMean(dataMat):
# 白化
meanVal = np.mean(dataMat, axis=0)
newData = dataMat - meanVal
return newData, meanVal
newData, meanVal = zeroMean(data)
covMat = np.cov(data, rowvar=0)
# 提取特征值和特征向量
eigVals, eigVects = np.linalg.eig(np.mat(covMat))
print "特征值:"
print eigVals
print "特征向量:"
print eigVects
# 降低维度
k = 1 # 期望降低维度
eigValIndice = np.argsort(eigVals) # 从小到大排序
n_eigValIndice = eigValIndice[-1:-(k+1):-1] # 取值最大的k个下标
n_eigVect = eigVects[:, n_eigValIndice] # 取对应的k个特征向量
lowDataMat = newData*n_eigVect
print "低维度空间:"
print lowDataMat
print "重构数据:"
reconMat = (lowDataMat * n_eigVect.T) + meanVal
print reconMat
为了便于观看和学习,输出数据咱们就放到这里了。
python
原始数据:
[[2.5 2.4]
[0.5 0.7]
[2.2 2.9]
[1.9 2.2]
[3.1 3. ]
[2.3 2.7]
[2. 1.6]
[1. 1.1]
[1.5 1.6]
[1.1 0.9]]
特征值:
[0.0490834 1.28402771]
特征向量:
[[-0.73517866 -0.6778734 ]
[ 0.6778734 -0.73517866]]
低维度空间:
[[-0.82797019]
[ 1.77758033]
[-0.99219749]
[-0.27421042]
[-1.67580142]
[-0.9129491 ]
[ 0.09910944]
[ 1.14457216]
[ 0.43804614]
[ 1.22382056]]
重构数据:
[[2.37125896 2.51870601]
[0.60502558 0.60316089]
[2.48258429 2.63944242]
[1.99587995 2.11159364]
[2.9459812 3.14201343]
[2.42886391 2.58118069]
[1.74281635 1.83713686]
[1.03412498 1.06853498]
[1.51306018 1.58795783]
[0.9804046 1.01027325]]
## 进一步
根据上面对PCA的数学原理的解释,我们可以了解到一些PCA的能力和限制。PCA本质上是将方差最大的方向作为主要特征,并且在各个正交方向上将数据“离相关”,也就是让它们在不同正交方向上没有相关性。如果处理不相关特征,可以了解一些关于流行学习的知识。
**PCA也存在一些限制,例如它可以很好的解除线性相关,但是对于高阶相关性就没有办法了**
## 备注
1: 去除相关性是什么鬼?其实对于我们的大多数的机器学习算法来讲,都是假设我们的特征是独立的,不希望有些特征是相互影响的,所以主成分分析算法,还有一个左右就是将相关性的特征进行剥离,抽取最重要的特征。
2: 在统计学与概率论中,散布矩阵是一个矩阵,其每个元素是各个向量元素之间的协方差。是从标量随机变量到高维度随机向量的自然推广。