You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
pqxin6emf/Part2/Chapter5/5.3 无监督学习/最重要的才是我想要的---PCA.md

8.1 KiB

5.3.4 最重要的才是我想要的---PCA

维数灾难

在机器学习中,我们不仅需要学习怎样进行分类、回归或者聚类,我们更要学习怎样对数据进行更好的处理,使得我们的数据能够更好的为我们的机器学习算法服务。而降维就是数据处理中的一环。

说到降维,那首先就要提到一个概念:维数灾难维数灾难其实很好理解,举个例子。

我们现在玩个游戏,我告诉你一些信息,你猜一猜我所描述的是什么。

  • 我:这个能在地球上才有,而且是犬科动物。
  • 您:......

如果您现在是一个动物的分类器,我相信您仅仅靠这两个特征(地球上才有,犬科动物)不大可能能够预测出我所说的是什么。也就是说,不管你用什么算法去分类,都很有可能发生欠拟合的现象。

  • 我:这个是犬科动物,喜欢啃骨头,长得像狼, 比较二。
  • 您:哈士奇!
  • 我:猜的挺准。

当我给出的信息比较合适(这次有4个特征),您可能能够猜到所提供的特征数据所描述的是哈士奇。这个时候我们的分类算法能正常工作。

  • 我:这个能在地球上才有,是犬科动物,有毛,有爪子,体型大,耳尖呈圆形,尾巴喜欢上翘,长得像狼,喜欢啃骨头,有时比较二但挺忠诚。
  • 您:哈士奇!
  • 我:不,我说的是阿拉斯加。
  • 您:......

这次我提供的信息比上面个两次都多(这次有10个特征),但是您可能将阿拉斯加误判成哈士奇。因为您可能看到长得像狼和比较二就认为是哈士奇了,也就是发生了过拟合的现象。这也说明了不是说数据的特征数量越多,我们的机器学习算法的效果就越强。当数据的特征数量变大时,和可能会造成机器学习算法的模型变得非常复杂,从而导致过拟合。而且如果我所提供的特征数量越多,比如有10000个特征,那么算法的训练过程中的时间成本会非常大。

所以维数灾难通常是指对于已知样本数目,存在一个特征数目的最大值,当实际使用的特征数目超过这个最大值时,机器学习算法的性能不是得到改善,而是退化。

降维

既然维数太大可能引发维数灾难,那么如果能有算法能够自动的帮我们把重要性比较高的特征维度保留下来,把其他的维度过滤掉就好了。那这个过程我们称之为降维

从维数灾难的概念出发,我们就能知道降维的作用了。

  • 降低机器学习算法的时间复杂度
  • 节省了提取不必要特征的开销
  • 缓解因为维数灾难所造成的过拟合现象

PCA与降维

降维的方法有很多,而最为常用的就是**PCA(主成分分析)。PCA是将数据从原来的坐标系转换到新的坐标系,新的坐标系的选择是由数据本身决定的。第一个新坐标轴选择的是原始数据中方差最大的方向**,第二个新坐标轴的选择和第一个坐标轴正交方差最大的方向。然后该过程一直重复,重复次数为原始数据中的特征数量。最后会发现大部分方差都包含在最前面几个新坐标轴中,因此可以忽略剩下的坐标轴,从而达到降维的目的。

PCA的算法流程

PCA在降维时,需要指定将维度降至多少维,假设降至k维,则PCA的算法流程如下:

  1. demean
  2. 计算数据的协方差矩阵
  3. 计算协方差矩阵的特征值与特征向量
  4. 按照特征值,将特征向量从大到小进行排序
  5. 选取前k个特征向量作为转换矩阵
  6. 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时两个特征之间没有任何相关关系。

协方差的数学定义如下(假设样本有xy两种特征,而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}

假设样本只有XY这两个特征,现在把XXXYYXYY的协方差组成矩阵,那么就构成了协方差矩阵。而协方差矩阵反应的就是特征与特征之间的相关关系。

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算法伪代码如下:

#假设数据集为DPCA后的特征数量为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