8.1 KiB
5.3.4 最重要的才是我想要的---PCA
维数灾难
在机器学习中,我们不仅需要学习怎样进行分类、回归或者聚类,我们更要学习怎样对数据进行更好的处理,使得我们的数据能够更好的为我们的机器学习算法服务。而降维就是数据处理中的一环。
说到降维,那首先就要提到一个概念:维数灾难。维数灾难其实很好理解,举个例子。
我们现在玩个游戏,我告诉你一些信息,你猜一猜我所描述的是什么。
- 我:这个能在地球上才有,而且是犬科动物。
- 您:......
如果您现在是一个动物的分类器,我相信您仅仅靠这两个特征(地球上才有,犬科动物)不大可能能够预测出我所说的是什么。也就是说,不管你用什么算法去分类,都很有可能发生欠拟合的现象。
- 我:这个是犬科动物,喜欢啃骨头,长得像狼, 比较二。
- 您:哈士奇!
- 我:猜的挺准。
当我给出的信息比较合适(这次有4
个特征),您可能能够猜到所提供的特征数据所描述的是哈士奇。这个时候我们的分类算法能正常工作。
- 我:这个能在地球上才有,是犬科动物,有毛,有爪子,体型大,耳尖呈圆形,尾巴喜欢上翘,长得像狼,喜欢啃骨头,有时比较二但挺忠诚。
- 您:哈士奇!
- 我:不,我说的是阿拉斯加。
- 您:......
这次我提供的信息比上面个两次都多(这次有10
个特征),但是您可能将阿拉斯加误判成哈士奇。因为您可能看到长得像狼和比较二就认为是哈士奇了,也就是发生了过拟合的现象。这也说明了不是说数据的特征数量越多,我们的机器学习算法的效果就越强。当数据的特征数量变大时,和可能会造成机器学习算法的模型变得非常复杂,从而导致过拟合。而且如果我所提供的特征数量越多,比如有10000
个特征,那么算法的训练过程中的时间成本会非常大。
所以维数灾难通常是指对于已知样本数目,存在一个特征数目的最大值,当实际使用的特征数目超过这个最大值时,机器学习算法的性能不是得到改善,而是退化。
降维
既然维数太大可能引发维数灾难,那么如果能有算法能够自动的帮我们把重要性比较高的特征维度保留下来,把其他的维度过滤掉就好了。那这个过程我们称之为降维。
从维数灾难的概念出发,我们就能知道降维的作用了。
- 降低机器学习算法的时间复杂度
- 节省了提取不必要特征的开销
- 缓解因为维数灾难所造成的过拟合现象
PCA与降维
降维的方法有很多,而最为常用的就是**PCA
(主成分分析)。PCA
是将数据从原来的坐标系转换到新的坐标系,新的坐标系的选择是由数据本身决定的。第一个新坐标轴选择的是原始数据中方差最大的方向**,第二个新坐标轴的选择和第一个坐标轴正交且方差最大的方向。然后该过程一直重复,重复次数为原始数据中的特征数量。最后会发现大部分方差都包含在最前面几个新坐标轴中,因此可以忽略剩下的坐标轴,从而达到降维的目的。
PCA的算法流程
PCA
在降维时,需要指定将维度降至多少维,假设降至k
维,则PCA
的算法流程如下:
demean
- 计算数据的协方差矩阵
- 计算协方差矩阵的特征值与特征向量
- 按照特征值,将特征向量从大到小进行排序
- 选取前
k
个特征向量作为转换矩阵 demean
后的数据与转换矩阵做矩阵乘法获得降维后的数据
其中**demean
,协方差矩阵,特征值与特征向量**的相关知识如下:
demean
demean
又称为零均值化,意思是将数据中每个维度上的均值变成0
。那为什么要这样做呢?PCA
实质上是找方差最大的方向,而方差的公式如下(其中\mu$$为均值):
Var(x)=\frac{1}{n}\sum_{i=1}^n(x-\mu)^2
如果将均值变成0
,那么方差计算起来就更加方便,如下:
Var(x)=\frac{1}{n}\sum_{i=1}^n(x)^2
在numpy
中想要demean
很简单,代码如下:
import numpy as np
#计算样本各个维度的均值
u = np.mean(data, axis=0)
#demean
after_demean = data - u
协方差矩阵
协方差描述的是两个特征之间的相关性,当协方差为正时,两个特征呈正相关关系(同增同减);当协方差为负时,两个特征呈负相关关系(一增一减);当协方差为0时,两个特征之间没有任何相关关系。
协方差的数学定义如下(假设样本有x
和y
两种特征,而X
就是包含所有样本的x
特征的集合,Y
就是包含所有样本的y
特征的集合):
conv(X, Y) = \frac{\sum_{i=1}^n(x_i-\mu_x)\sum_{i=1}^n(y_i-\mu_y)}{n-1}
如果在算协方差之前做了demean
操作,那么公式则为:
conv(X, Y) = \frac{\sum_{i=1}^nx_i\sum_{i=1}^ny_i}{n-1}
假设样本只有X
和Y
这两个特征,现在把X
与X
,X
与Y
,Y
与X
,Y
与Y
的协方差组成矩阵,那么就构成了协方差矩阵。而协方差矩阵反应的就是特征与特征之间的相关关系。
X | Y | |
---|---|---|
X | conv(X,X) | conv(X,Y) |
Y | conv(Y,X) | conv(Y,Y) |
NumPy
提供了计算协方差矩阵的函数cov
,示例代码如下:
import numpy as np
# 计算after_demean的协方差矩阵
# after_demean的行数为样本个数,列数为特征个数
# 由于cov函数的输入希望是行代表特征,列代表数据的矩阵,所以要转置
cov = np.cov(after_demean.T)
特征值与特征向量
特征值与特征向量的数学定义:如果向量v
与矩阵A
满足Av=λv
,则称向量v
是矩阵A的一个特征向量,λ
是相应的特征值。
因为协方差矩阵为方阵,所以我们可以计算协方差矩阵的特征向量和特征值。其实这里的特征值从某种意义上来说体现了方差的大小,特征值越大方差就越大。而特征值所对应的特征向量就代表将原始数据进行坐标轴转换之后的数据。
numpy
为我们提供了计算特征值与特征向量的接口eig
,示例代码如下:
import numpy as np
#eig函数为计算特征值与特征向量的函数
#cov为矩阵,value为特征值,vector为特征向量
value, vector = np.linalg.eig(cov)
因此,PCA
算法伪代码如下:
#假设数据集为D,PCA后的特征数量为k
def pca(D, k):
after_demean=demean(D)
计算after_demean的协方差矩阵cov
value, vector = eig(cov)
根据特征值value将特征向量vector降序排序
筛选出前k个特征向量组成映射矩阵P
after_demean和P做矩阵乘法得到result
return result
sklearn中的PCA
PCA
的构造函数中有一个常用的参数可以设置:
n_components
:表示想要将数据降维至n_components
个维度
PCA
类中有三个常用的函数分别为:fit
函数用于训练PCA
模型;transform
函数用于将数据转换成降维后的数据,当模型训练好后,对于新输入的数据,也可以用transform
方法来降维;fit_transform
函数用于使用数据训练PCA
模型,同时返回降维后的数据。
其中fit
函数中的参数:
X
:大小为[样本数量,特征数量]
的ndarray
,存放训练样本
transform
函数中的参数:
X
:大小为[样本数量,特征数量]
的ndarray
,存放训练样本
fit_transform
函数中的参数:
X
:大小为[样本数量,特征数量]
的ndarray
,存放训练样本
PCA
的使用代码如下:
from sklearn.decomposition import PCA
#构造一个将维度降至11维的PCA对象
pca = PCA(n_components=11)
#对数据X进行降维,并将降维后的数据保存至newX
newX = pca.fit_transform(X)
如果想动手实现PCA
算法,并掌握如何使用sklearn
来解决实际问题,可以尝试进入链接进行实战:https://www.educoder.net/shixuns/rbnaxywe/challenges