92scikit-learn 机器学习入门实战--PCA 主成分分析应用

PCA 主成分分析应用

主成分分析

主成分分析 是多元线性统计里面的概念,它的英文是 Principal Components Analysis,简称 PCA。主成分分析旨在降低数据的维数,通过保留数据集中的主要成分来简化数据集。简化数据集在很多时候是非常必要的,因为复杂往往就意味着计算资源的大量消耗。通过对数据进行降维,我们就能在结果不受影响或受略微影响的同时,减少模型学习时间。
特别强调的是,本次实验所说的降维,不是指降低 NumPy 数组的维度,而是特指减少样本的特征数量。

image.png

上图展示了把三维空间的数据降维到二维空间的过程。
下面,介绍一下 scikit-learn 中 PCA 方法的参数定义及简单使用,这是完成 PCA 主成分分析的基础。

sklearn.decomposition.PCA(n_components=None, copy=True, whiten=False, svd_solver='auto')

其中:
n_components= 表示需要保留主成分(特征)的数量。
copy= 表示针对原始数据降维还是针对原始数据副本降维。当参数为 False 时,降维后的原始数据会发生改变,这里默认为 True。
whiten= 白化表示将特征之间的相关性降低,并使得每个特征具有相同的方差。
svd_solver= 表示奇异值分解 SVD 的方法。有 4 个参数,分别是:auto, full, arpack, randomized。

我们生成一个最容易可视化降维过程的二维数据集来看下:

import numpy as np
import matplotlib.pyplot as plt
from scipy import stats
%matplotlib inline

plt.style.use('seaborn')  # 样式美化

# 当我们设置相同的seed时,每次生成的随机数也相同,如果不设置seed,则每次生成的随机数都会不一样
np.random.seed(1)
X = np.dot(np.random.random(size=(2, 2)),
           np.random.normal(size=(2, 200))).T  # 生成二维数据
plt.plot(X[:, 0], X[:, 1], 'o')
plt.axis('equal')

我们可以看到数据有一个明确的趋势。PCA 要做的就是在数据中找到主轴,并解释这些轴在描述数据分布中的重要性:

# 导入 PCA 估计器
from sklearn.decomposition import PCA

pca = PCA(n_components=2)  # 保留两个特征(维度)
pca.fit(X)
print(pca.explained_variance_)
print(pca.components_)

我们看到了两个输出,要了解这些数字的含义,让我们将其视为向量在数据点上绘制出来:

plt.plot(X[:, 0], X[:, 1], 'o', alpha=0.5)

for length, vector in zip(pca.explained_variance_, pca.components_):
    v = vector * 3 * np.sqrt(length)
    plt.plot([0, v[0]], [0, v[1]], '-k', lw=3)  # lw设置线宽
plt.axis('equal')

绘图结果来看,一个向量比另一个向量长。从某种意义上讲,这告诉我们数据中的这个方向比另一个方向更“重要”,而这种方向上的“重要性”是用方差来量化的。当然这也告诉我们,在不损失大量信息的情况下完全可以忽略第二个主要成分。让我们看看如果仅保留 95%的方差,数据将是什么样子:

clf = PCA(0.95)  # 保存 95%的方差
X_trans = clf.fit_transform(X)
print(X.shape)
print(X_trans.shape)

在使用 PCA 降维时,我们也会使用到 PCA.fit() 方法。.fit() 是 scikit-learn 训练模型的通用方法,但是该方法本身返回的是模型的参数。所以,通常我们会使用 PCA.fit_transform() 方法直接返回降维后的数据结果。
上面结果来看,通过舍弃 5%的方差,数据从 2 维变成了 1 维,相当于压缩了 50%。让我们看看压缩后的数据是什么样的:

# 将降维后的数据转换成原始数据的维度,才能绘图
X_new = clf.inverse_transform(X_trans)
plt.plot(X[:, 0], X[:, 1], 'o', alpha=0.2)
plt.plot(X_new[:, 0], X_new[:, 1], 'ob', alpha=0.8)
plt.axis('equal')

暗一点的是原始数据,而亮一点的是投影版本。我们看到将这个数据集的方差截断 5%再重新投影之后,数据“最重要”的功能得以保留,并且我们将数据压缩了 50%,这也就是降维的意义:如果可以在较低维度上得到近似数据集,则我们可以更轻松地查看它或将更复杂的模型拟合到数据中。

PCA 手写数字数据集应用

降维在二维数据上似乎表现得没有那么重要,但是在可视化高维数据时,投影和降维非常有用。让我们看一下 PCA 在我们之前看过的手写数字识别数据中的应用:

# 导入数据集模块
from sklearn.datasets import load_digits
digits = load_digits()  # 载入数据集
X = digits.data
y = digits.target

pca = PCA(n_components=2)  # 从 64 维降维到 2 维
Xproj = pca.fit_transform(X)
print(X.shape)  # 查看原数据
print(Xproj.shape)  # 查看降维后的数据

# 绘制降维后的数据散点图
plt.scatter(Xproj[:, 0], Xproj[:, 1], c=y, edgecolor='none', alpha=0.5,
            cmap=plt.cm.get_cmap('nipy_spectral', 10))
plt.colorbar()  # 绘制色标

我们将 64 维的数据降到了 2 维,并将其可视化绘制出来,这使我们对数字之间的关系有了一个概念,并且使我们无需参考标签即可查看数字的布局。
之前,我们用支持向量机完成了分类,即预测哪一张图像代表哪一个数字。现在,我们采用相同的数据集完成聚类分析,即将全部数据集聚为 10 个类别。
我们将降到 2 维后的数据聚为 10 类,并将聚类后的结果、聚类中心点、聚类决策边界绘制出来。

from sklearn.cluster import KMeans

pca = PCA(n_components=2)  # 从 64 维降维到 2 维
Xproj = pca.fit_transform(X)

# 建立 K-Means 并输入数据
model = KMeans(n_clusters=10)
model.fit(Xproj)

# 计算聚类过程中的决策边界
x_min, x_max = Xproj[:, 0].min() - 1, Xproj[:, 0].max() + 1
y_min, y_max = Xproj[:, 1].min() - 1, Xproj[:, 1].max() + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, .05),
                     np.arange(y_min, y_max, .05))  # 生成网格点坐标矩阵

result = model.predict(np.c_[xx.ravel(), yy.ravel()])

# 绘制决策边界
result = result.reshape(xx.shape)
plt.figure(figsize=(10, 5))
plt.contourf(xx, yy, result, cmap=plt.cm.Greys)  # 绘制填充色
plt.scatter(Xproj[:, 0], Xproj[:, 1], c=y, edgecolor='none', alpha=0.5,
            cmap=plt.cm.get_cmap('nipy_spectral', 10))  # 绘制数据散点图
plt.colorbar()  # 绘制色标

# 绘制聚类中心点
center = model.cluster_centers_
plt.scatter(center[:, 0], center[:, 1], marker='p',
            linewidths=2, color='b', edgecolors='w', zorder=20)

# 图像参数设置
plt.xlim(x_min, x_max)
plt.ylim(y_min, y_max)

图中,不同的色块区域代表一类。这里色块的颜色没有意义,只表示类别。散点代表数据,散点的颜色表示数据原始类别。我们可以看出,虽然原始数据已经降到了 2 维,但某几个数字的依旧有明显的成团现象。
除此之外,我们还可以使用分类方法来对比降维前后的数据表现。我们使用随机森林方法对数据进行分类,并通过交叉验证得到准确度结果。

from sklearn.ensemble import RandomForestClassifier  # 导入随机森林估计器
from sklearn.model_selection import cross_val_score  # 导入交叉验证

model = RandomForestClassifier()

# 5 折交叉验证平均准确度
s1 = cross_val_score(model, X, y, cv=5).mean()  # 原始维度数据
s2 = cross_val_score(model, Xproj, y, cv=5).mean()  # 降维后的数据
print(s1)
print(s2)

你可以看到,实际上准确度并不是特别低。也就是说,在客观条件限制下,我们往往可以以更少维度的数据训练出准确度可以勉强接受的模型。

其他降维估计器

scikit-learn 还包含许多其他无监督学习的降维估计器,你可以尝试其他的降维方法:
sklearn.decomposition.IncrementalPCA:增量主成分分析(IPCA)
sklearn.decomposition.SparsePCA:PCA 变体,包括 L1 正则
sklearn.decomposition.FastICA:独立成分分析
sklearn.decomposition.NMF:非负矩阵分解
sklearn.manifold.LocallyLinearEmbedding:基于局部邻域几何的非线性流形学习
sklearn.manifold.IsoMap:基于稀疏图算法的非线性流形学习

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,504评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,434评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,089评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,378评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,472评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,506评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,519评论 3 413
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,292评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,738评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,022评论 2 329
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,194评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,873评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,536评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,162评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,413评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,075评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,080评论 2 352

推荐阅读更多精彩内容