机器学习——主成分分析PCA


机器学习十大算法——主成分分析 PCA(principal components analysis)

降维

宇宙,是时间和空间的总和。时间是一维的,而空间的维度,众说纷纭,至今没有定论。弦理论说是9维,霍金所认同M理论则认为是10维。它们解释说人类所能感知的三维以外的维度都被卷曲在了很小的空间尺度内。当然,谈及这些并不是为了推销《三体》系列读物,更不是引导读者探索宇宙真谛,甚至怀疑人生本质,而是为了引出今天机器学习课堂主题——降维。

机器学习中的数据维数与现实世界的空间维度本同末离。在机器学习中,数据通常需要被表示成向量形式以输入模型进行训练。但众所周知,对高维向量进行处理和分析时,会极大消耗系统资源,甚至产生维度灾难。例如在CV(计算机视觉)领域中将一幅100x100的RGB图像提取像素特征,维度将达到30000;在NLP(自然语言处理)领域中建立<文档-词>特征矩阵,也动辄产生几万维的特征向量。因此,进行降维,即用一个低维度的向量表示原始高维度的特征就显得尤为重要。试想,如果宇宙真如M理论所说,每个天体的位置都由一个十维坐标来描述,应该没有一个正常人能想象出其中的空间构造。但当我们把这些星球投影到一个二维平面,整个宇宙便会像上面的银河系一样直观起来。

常见的降维方法主要有主成分分析(PCA)、线性判别分析(LDA)、等距映射(Isomap)、局部线性嵌入(LLE)、拉普拉斯特征映射(LE)、局部保留投影(LPP)等。这些方法又可以按照线性/非线性,监督/非监督,全局/局部,进行不同划分。其中 PCA作为最经典的方法,至今已有100多年的历史,它属于一种线性、非监督、全局的降维算法。我们今天就来回顾一下这经久不衰的百年经典。

主成分分析属于统计学的方法,过正交变换将一组可能存在相关性的变量转换为一组线性不相关的变量,转换后的这组变量叫主成分。

在这里插入图片描述

主成分分析的一些实际应用包括数据压缩,简化数据表示,数据可视化等。值得一提的是需要领域知识来判断是否适合使用主成分分析算法。如果数据的噪声太大(即各个成分的方差都很大),就不适合使用主成分分析算法。

PCA 算法

PCA的原理及目标函数

PCA(principal components analysis), 即主成分分析,旨在找到数据中的主成分,并利用这些主成分表征原始数据,从而达到降维的目的。举一个简单的例子,在三维空间中有一系列数据点,这些点分布在一个过原点的平面上。如果我们用自然坐标系x, y, z这三个轴来表示数据,需要使用三个维度,而实际上这些点只出现在一个二维平面上,如果我们通过坐标系旋转使得数据所在平面与x, y平面重合,那么我们就可以通过x’, y’两个维度表达原始数据,并且没有任何损失,这样就完成了数据的降维,而x’, y’两个轴所包含的信息就是我们要找到的主成分。

但在高维空间中,我们往往不能像刚才这样直观地想象出数据的分布形式,也就更难精确地找到主成分对应的轴是哪些。不妨,我们先从最简单的二维数据来看看PCA究竟是如何工作的。
在这里插入图片描述
上图(左)是二维空间中经过中心化的一组数据,我们很容易看出主成分所在的轴(以下称为主轴)的大致方向,即右图中绿线所处的轴。因为在绿线所处的轴上,数据分布的更为分散,这也意味着数据在这个方向上方差更大。在信号处理领域中我们认为信号具有较大方差,噪声具有较小方差,信号与噪声之比称为信噪比,信噪比越大意味着数据的质量越好。由此我们不难引出PCA的目标,即最大化投影方差,也就是让数据在主轴上投影的方差最大。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
如果你收到任何形状的数据,PCA从旧坐标系仅通过转化和轮换获得新坐标系系统,它根据数据中心将坐标系中心移至数据中心,将x轴移至变化的主轴,在整个数据集中寻找它最大方差的位置。它将进一步将轴移至正交处重要性较低的变化方向。
在这里插入图片描述

给定一些房屋的参数,如果想预测它的价格,该使用以下那个算法呢?
□ 决策树分类器
□ SVC
□ 线性回归

很明显是:线性回归

PCA的求解方法

熟悉线性代数的读者马上就会发现,原来,x投影后的方差就是协方差矩阵的特征值。我们要找到最大的方差也就是协方差矩阵最大的特征值,最佳投影方向就是最大特征值所对应特征向量。次佳投影方向位于最佳投影方向的正交空间中,是第二大特征值对应的特征向量,以此类推。至此,我们得到了PCA的求解方法:

在这里插入图片描述
在这里插入图片描述

PCA 最小平方误差理论

问题描述

观察到其实PCA求解的是最佳投影方向,即一条直线,这与数学中线性回归问题的目标不谋而合,能否从回归的角度定义PCA的目标并相应地求解问题呢?

分析

在这里插入图片描述

我们还是考虑二维空间这些样本点,最大方差角度求解的是一条直线,使得样本点投影到这条直线上的方差最大。从求解直线的思路出发,很容易联想到数学中的线性回归问题,其目标也是求解一个线性函数使得对应直线能够更好地拟合样本点集合。如果我们从这个角度定义PCA的目标,那么问题就会转化为一个回归问题。

顺着这个思路,在高维空间中,我们实际上是要找到一个d维超平面,使得数据点到这个超平面的距离平方和最小。对于一维的情况,超平面退化为直线,即把样本点投影到最佳直线,最小化的就是所有点到直线的距离平方之和,如下图所示。
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

第一项xkTxk与我们选取的W无关,是个常数。我们利用刚才求出的投影向量表示将第二项和第三项分别继续展开
在这里插入图片描述
其中ωiTxk和ωjTxk表示投影长度,都是数字。且i≠j时,ωiTωj=0,因此上式的交叉项中只剩下d项。

在这里插入图片描述
我们要最小化的式子即对所有的k求和,可以写成
在这里插入图片描述

如果我们对W中的d个基ω1, ω2, …, ωd依次求解,就会发现和上一节中方法完全等价。比如当d=1时,我们实际求解的问题是
在这里插入图片描述
这个最佳直线ω与最大方差法求解的最佳投影方向一致,即协方差矩阵的最大特征值所对应的特征向量,差别仅是协方差矩阵∑的一个倍数,以及一个常数偏差,但这并不影响我们对最大值的优化。

PCA与方差

方差,数据分布的大致差幅。对于一个具有较大方差的特征,它的样本散布的值范围很大,若方差较小,则各项特征通常是紧密聚集在一起的。

主成分是由最大方差的那个方向决定的。

我们沿着最大方差的维度进行映射时,它能够保持原始数据中最多的信息。使信息
丢失的总的可能性最小。在这里插入图片描述

用于特征转换的PCA
在这里插入图片描述

假设你的数据集里有100个训练点,每个点有4个特征,在 sklearn 允许的范围内,你利用其他的 PCA 实现方式所能找到的主要成分的最大数量是多少?
应该为 min(4,100) = 4

PCA特点总结

1.PCA是将输入特征转化为其主成分的系统化方式;

2.这些主成分之后可供你使用,而不是原始输入特征,你将其用作回归或者分类任务中的新特征。

3.主成分的定义是数据中会使方差最大化的方向。它可以在你对这些主成分执行投影或者压缩时,将出现信息丢失的可能性降至最低。

4.可以对主成分划分等级,数据因特定主成分产生的方差越大,那么该主成分的级别越高。因此,产生方差最大的主成分为第一主成分。

5.主成分在某种意义上时相互垂直的。因此,从数学角度上讲,第二主成分绝对不会与第一主成分重叠。因此,某种意义上,你可以将他们当做单独的特征对待

6.主成分数量是有上限的。最大值等于数据集中的输入特征数量,通常情况下,你只会使用前几个主成分。

什么时候使用PCA

  1. 如果你想要访问隐藏的特征,而你认为这些特征可能显示在你的数据的图案中,你要做的所有工作可能就是要确定是否存在隐藏的特征,也就是说,你只想知道第一个主成分的大小。
  2. 降维
    2.1帮你可视化高维数据
    2.2 减少噪声, 较大的主成分表示主要数据,较小的主成分表示可能的噪声,抛弃小的主成分即可消除噪声
    2.3 在使用另一个算法之前,先用PCA进行预处理。也就是归纳或分类任务

为什么PCA在人脸识别中有不错的应用呢?

1.人脸照片通常有很高的输入维度(很多像素)
2. 人脸具有一些一般性形态,这些形态可以以较小维数的方式捕捉,比如人一般都有两只眼睛,眼睛基本都位于接近脸的顶部的位置

eigenface PCA

"""
===================================================
Faces recognition example using eigenfaces and SVMs
===================================================

The dataset used in this example is a preprocessed excerpt of the
"Labeled Faces in the Wild", aka LFW_:

  http://vis-www.cs.umass.edu/lfw/lfw-funneled.tgz (233MB)

  .. _LFW: http://vis-www.cs.umass.edu/lfw/

  original source: http://scikit-learn.org/stable/auto_examples/applications/face_recognition.html

"""



print __doc__

from time import time
import logging
import pylab as pl
import numpy as np

from sklearn.cross_validation import train_test_split
from sklearn.datasets import fetch_lfw_people
from sklearn.grid_search import GridSearchCV
from sklearn.metrics import classification_report
from sklearn.metrics import confusion_matrix
from sklearn.decomposition import RandomizedPCA
from sklearn.svm import SVC

# Display progress logs on stdout
logging.basicConfig(level=logging.INFO, format='%(asctime)s %(message)s')


###############################################################################
# Download the data, if not already on disk and load it as numpy arrays
lfw_people = fetch_lfw_people(min_faces_per_person=70, resize=0.4)

# introspect the images arrays to find the shapes (for plotting)
n_samples, h, w = lfw_people.images.shape
np.random.seed(42)

# for machine learning we use the data directly (as relative pixel
# position info is ignored by this model)
X = lfw_people.data
n_features = X.shape[1]

# the label to predict is the id of the person
y = lfw_people.target
target_names = lfw_people.target_names
n_classes = target_names.shape[0]

print "Total dataset size:"
print "n_samples: %d" % n_samples
print "n_features: %d" % n_features
print "n_classes: %d" % n_classes


###############################################################################
# Split into a training and testing set
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=42)

###############################################################################
# Compute a PCA (eigenfaces) on the face dataset (treated as unlabeled
# dataset): unsupervised feature extraction / dimensionality reduction
n_components = 150

print "Extracting the top %d eigenfaces from %d faces" % (n_components, X_train.shape[0])
t0 = time()
pca = RandomizedPCA(n_components=n_components, whiten=True).fit(X_train)
print "done in %0.3fs" % (time() - t0)

eigenfaces = pca.components_.reshape((n_components, h, w))

print "Projecting the input data on the eigenfaces orthonormal basis"
t0 = time()
X_train_pca = pca.transform(X_train)
X_test_pca = pca.transform(X_test)
print "done in %0.3fs" % (time() - t0)


###############################################################################
# Train a SVM classification model

print "Fitting the classifier to the training set"
t0 = time()
param_grid = {
         'C': [1e3, 5e3, 1e4, 5e4, 1e5],
          'gamma': [0.0001, 0.0005, 0.001, 0.005, 0.01, 0.1],
          }
# for sklearn version 0.16 or prior, the class_weight parameter value is 'auto'
clf = GridSearchCV(SVC(kernel='rbf', class_weight='balanced'), param_grid)
clf = clf.fit(X_train_pca, y_train)
print "done in %0.3fs" % (time() - t0)
print "Best estimator found by grid search:"
print clf.best_estimator_


###############################################################################
# Quantitative evaluation of the model quality on the test set

print "Predicting the people names on the testing set"
t0 = time()
y_pred = clf.predict(X_test_pca)
print "done in %0.3fs" % (time() - t0)

print classification_report(y_test, y_pred, target_names=target_names)
print confusion_matrix(y_test, y_pred, labels=range(n_classes))


###############################################################################
# Qualitative evaluation of the predictions using matplotlib

def plot_gallery(images, titles, h, w, n_row=3, n_col=4):
    """Helper function to plot a gallery of portraits"""
    pl.figure(figsize=(1.8 * n_col, 2.4 * n_row))
    pl.subplots_adjust(bottom=0, left=.01, right=.99, top=.90, hspace=.35)
    for i in range(n_row * n_col):
        pl.subplot(n_row, n_col, i + 1)
        pl.imshow(images[i].reshape((h, w)), cmap=pl.cm.gray)
        pl.title(titles[i], size=12)
        pl.xticks(())
        pl.yticks(())


# plot the result of the prediction on a portion of the test set

def title(y_pred, y_test, target_names, i):
    pred_name = target_names[y_pred[i]].rsplit(' ', 1)[-1]
    true_name = target_names[y_test[i]].rsplit(' ', 1)[-1]
    return 'predicted: %s\ntrue:      %s' % (pred_name, true_name)

prediction_titles = [title(y_pred, y_test, target_names, i)
                         for i in range(y_pred.shape[0])]

plot_gallery(X_test, prediction_titles, h, w)

# plot the gallery of the most significative eigenfaces

eigenface_titles = ["eigenface %d" % i for i in range(eigenfaces.shape[0])]
plot_gallery(eigenfaces, eigenface_titles, h, w)

pl.show()

在这里插入图片描述
在这里插入图片描述

第一主成分解释了多少变异量?第二主成分呢?

print "the raio is ", pca.explained_variance_ratio_

输出结果为

the raio is  [ 0.19346527  0.15116846  0.07083679  0.05951796  0.05157495  0.02887154
  0.02514484  0.02176464  0.0201938   0.01902123  0.01682212  0.01580598
  0.01223363  0.01087937  0.01064452  0.00979653  0.00892399  0.00854844
  0.00835711  0.00722635  0.00696569  0.00653856  0.00639558  0.00561316
  0.00531106  0.00520151  0.00507464  0.00484208  0.00443587  0.00417828
  0.00393703  0.00381726  0.00356056  0.00351197  0.0033455   0.00329926
  0.00314617  0.0029621   0.00290122  0.00284714  0.00279994  0.00267543
  0.00259888  0.00258392  0.00240908  0.00238968  0.00235381  0.00222562
  0.00217477  0.00216539  0.0020899   0.00205378  0.002004    0.00197359
  0.00193792  0.00188721  0.00180128  0.0017884   0.0017479   0.00172996
  0.00165608  0.00162911  0.00157353  0.00153328  0.00149869  0.00147138
  0.0014378   0.00141799  0.00139597  0.00138007  0.00133829  0.00133086
  0.00128615  0.00125412  0.00124097  0.00121724  0.00120764  0.00117971
  0.00114917  0.00113298  0.00112154  0.00111338  0.00109026  0.00106596
  0.00105318  0.00103993  0.00102117  0.00101424  0.00099488  0.00095896
  0.00093924  0.00091411  0.0009067   0.00088578  0.00086823  0.0008575
  0.00083937  0.00083335  0.00082446  0.00079804  0.00077951  0.00077447
  0.00075076  0.00074372  0.0007379   0.00072589  0.00072071  0.00070336
  0.0006974   0.0006841   0.00065978  0.00065279  0.00064307  0.00062694
  0.0006201   0.00061201  0.00059858  0.00059774  0.00059178  0.0005793
  0.00056503  0.00055913  0.00055501  0.00054754  0.00053055  0.00051918
  0.00051402  0.00050243  0.00049237  0.00048626  0.00048497  0.00047697
  0.00046272  0.00045677  0.00044803  0.00044402  0.00044195  0.00042938
  0.00042588  0.00041862  0.00041062  0.00040071  0.00039972  0.00039405
  0.00038286  0.00037621  0.00036738  0.00035972  0.00035115  0.00034749]

所以,第一主成分解释了0.19346527 变异量?第二主成分是0.15116846

随着你添加越来越多的主成分作为训练分类器的特征,它的性能会更高。

如果你看到更高的 F1 得分,这意味着分类器的性能更高还是更低?

将 n_components 更改为以下值:[10, 15, 25, 50, 100, 250]。对于每个主成分,请注意 Ariel Sharon 的 F1 分数。(对于 10 个主成分,代码中的绘制功能将会失效,但你应该能够看到 F1 分数。)

如果看到较高的 F1 分数,这意味着分类器的表现是更好还是更差?

Ariel Sharon f-score

n_components = 10 f-score=0.11
n_components = 15 f-score=0.31
n_components = 50 f-score= 0.67
n_components = 100 f-score=0.67
n_components = 150 f-score=0.48
n_components = 250 f-score=0.6

F1 得分越高,这意味着分类器的性能更高。

当使用大量 主成分(PC) 时,你是否会看到任何过拟合迹象?

会,PC 较多时性能会下降,这时候F1-score会降低,所以造成了过拟合

选择主成分

在这里插入图片描述

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值