机器学习基础教程第三章 降维、特征提取与流形学习

3.4降维、特征提取与流形学习

3.4.1主成分分析

  1. 将 PCA 应用于 cancer 数据集并可视化 PCA 最常见的应用之一就是将高维数据集可视化。正如第 1 章中所说,对于有两个以上特 征的数据,很难绘制散点图。对于 Iris(鸢尾花)数据集,我们可以创建散点图矩阵(见 第 1 章图 1-3),通过展示特征所有可能的两两组合来展示数据的局部图像。但如果我们想 要查看乳腺癌数据集,即便用散点图矩阵也很困难。这个数据集包含 30 个特征,这就导 致需要绘制 30 * 14 = 420 张散点图!我们永远不可能仔细观察所有这些图像,更不用说试 图理解它们了。
    不过我们可以使用一种更简单的可视化方法——对每个特征分别计算两个类别(良性肿瘤 和恶性肿瘤)的直方图。
from sklearn.datasets import load_digits
import matplotlib.pyplot as plt
from sklearn.decomposition import PCA
import numpy as np
import mglearn
from sklearn.datasets import load_breast_cancer
cancer=load_breast_cancer()

fig, axes = plt.subplots(15, 2, figsize=(10, 20))
malignant = cancer.data[cancer.target == 0]
benign = cancer.data[cancer.target == 1]
ax = axes.ravel()
for i in range(30):
    _, bins = np.histogram(cancer.data[:, i], bins=50)
    ax[i].hist(malignant[:, i], bins=bins, color=mglearn.cm3(0), alpha=.5)
    ax[i].hist(benign[:, i], bins=bins, color=mglearn.cm3(2), alpha=.5)
    ax[i].set_title(cancer.feature_names[i])
    ax[i].set_yticks(())
ax[0].set_xlabel("Feature magnitude")
ax[0].set_ylabel("Frequency")
ax[0].legend(["malignant", "benign"], loc="best")
fig.tight_layout()

乳腺癌数据集中每个类别的特征直方图
在这里插入图片描述

利用 PCA,我们可以获取到主要的相互作用,并得到稍为完整的图像。我们可以找到前两 个主成分,并在这个新的二维空间中用散点图将数据可视化。
在应用 PCA 之前,我们利用 StandardScaler 缩放数据,使每个特征的方差均为 1:

from sklearn.preprocessing import StandardScaler
from sklearn.datasets import load_breast_cancer
cancer = load_breast_cancer()
scaler = StandardScaler()
scaler.fit(cancer.data)
X_scaled = scaler.transform(cancer.data)
from sklearn.decomposition import PCA
pca = PCA(n_components=2)
pca.fit(X_scaled)
X_pca = pca.transform(X_scaled)
print("Original shape: {}".format(str(X_scaled.shape)))
print("Reduced shape: {}".format(str(X_pca.shape)))

在这里插入图片描述

现在我们可以对前两个主成分作图

# 对第一个和第二个主成分作图,按类别着
plt.figure(figsize=(8, 8))
mglearn.discrete_scatter(X_pca[:, 0], X_pca[:, 1], cancer.target)
plt.legend(cancer.target_names, loc="best")
plt.gca().set_aspect("equal")
plt.xlabel("First principal component")
plt.ylabel("Second principal component")
print("PCA component shape: {}".format(pca.components_.shape))
print("PCA components:\n{}".format(pca.components_))

利用前两个主成分绘制乳腺癌数据集的二维散点图

在这里插入图片描述
PCA 是一种无监督方法,在寻找旋转方向时没有用到任何类别信息。它 只是观察数据中的相关性。对于这里所示的散点图,我们绘制了第一主成分与第二主成分 的关系,然后利用类别信息对数据点进行着色。你可以看到,在这个二维空间中两个类别 被很好地分离。这让我们相信,即使是线性分类器(在这个空间中学习一条直线)也可以 在区分这个两个类别时表现得相当不错。我们还可以看到,恶性点比良性点更加分散,这 一点也可以在图 3-4 的直方图中看出来。
PCA 的一个缺点在于,通常不容易对图中的两个轴做出解释。主成分对应于原始数据中的 方向,所以它们是原始特征的组合。但这些组合往往非常复杂,这一点我们很快就会看 到。在拟合过程中,主成分被保存在 PCA 对象的 components_ 属性中:

在这里插入图片描述

我们还可以用热图将系数可视化(图 3-6),这可能更容易理解:

plt.matshow(pca.components_, cmap='viridis')
plt.yticks([0, 1], ["First component", "Second component"])
plt.colorbar()
plt.xticks(range(len(cancer.feature_names)),
           cancer.feature_names, rotation=60, ha='left')
plt.xlabel("Feature")
plt.ylabel("Principal components")
plt.show()

图 3-6:乳腺癌数据集前两个主成分的热图
在这里插入图片描述

3.4.3 用t-SNE进行流形学习
流形学习算法主要用于可视化,因此很少用来生成两个以上的新特征。其中一些算法(包 括 t-SNE)计算训练数据的一种新表示,但不允许变换新数据。这意味着这些算法不能用于测试集:更确切地说,它们只能变换用于训练的数据。流形学习对探索性数据分析是很 有用的,但如果最终目标是监督学习的话,则很少使用。t-SNE 背后的思想是找到数据的 一个二维表示,尽可能地保持数据点之间的距离。t-SNE 首先给出每个数据点的随机二维 表示,然后尝试让在原始特征空间中距离较近的点更加靠近,原始特征空间中相距较远的 点更加远离。t-SNE 重点关注距离较近的点,而不是保持距离较远的点之间的距离。换句 话说,它试图保存那些表示哪些点比较靠近的信息。 我们将对 scikit-learn 包含的一个手写数字数据集 2 应用 t-SNE 流形学习算法。在这个数 据集中,每个数据点都是 0 到 9 之间手写数字的一张 8×8 灰度图像。图 3-20 给出了每个 类别的一个例子。

digits = load_digits()
fig, axes = plt.subplots(2, 5, figsize=(10, 5), subplot_kw={'xticks': (), 'yticks': ()})
for ax, img in zip(axes.ravel(), digits.images):
    ax.imshow(img)

digits 数据集的示例图
在这里插入图片描述
我们用 PCA 将降到二维的数据可视化。我们对前两个主成分作图,并按类别对数据点着 色

# 构建一个PCA模型
pca = PCA(n_components=2)
pca.fit(digits.data) # 将digits数据变换到前两个主成分的方向上
digits_pca = pca.transform(digits.data)
colors = ["#476A2A", "#7851B8", "#BD3430", "#4A2D4E", "#875525",           "#A83683", "#4E655E", "#853541", "#3A3120", "#535D8E"]
plt.figure(figsize=(10, 10))
plt.xlim(digits_pca[:, 0].min(), digits_pca[:, 0].max())
plt.ylim(digits_pca[:, 1].min(), digits_pca[:, 1].max())
for i in range(len(digits.data)):     # 将数据实际绘制成文本,而不是散点
    plt.text(digits_pca[i, 0], digits_pca[i, 1], str(digits.target[i]),
    color = colors[digits.target[i]],
    fontdict={'weight': 'bold', 'size': 9})
plt.xlabel("First principal component")
plt.ylabel("Second principal component")

利用前两个主成分绘制 digits 数据集的散点图

在这里插入图片描述
实际上,这里我们用每个类别对应的数字作为符号来显示每个类别的位置。利用前两个主 成分可以将数字 0、6 和 4 相对较好地分开,尽管仍有重叠。大部分其他数字都大量重叠 在一起。
我们将 t-SNE 应用于同一个数据集,并对结果进行比较。由于 t-SNE 不支持变换新数据, 所以 TSNE 类没有 transform 方法。我们可以调用 fit_transform 方法来代替

from sklearn.manifold import TSNE
tsne = TSNE(random_state=42)
# 使用fit_transform而不是fit,因为TSNE没有transform方法
digits_tsne = tsne.fit_transform(digits.data)
plt.figure(figsize=(10, 10))
plt.xlim(digits_tsne[:, 0].min(), digits_tsne[:, 0].max() + 1)
plt.ylim(digits_tsne[:, 1].min(), digits_tsne[:, 1].max() + 1)
for i in range(len(digits.data)):     # 将数据实际绘制成文本,而不是散点
    plt.text(digits_tsne[i, 0], digits_tsne[i, 1], str(digits.target[i]),
         color = colors[digits.target[i]],
         fontdict={'weight': 'bold', 'size': 9})
plt.xlabel("t-SNE feature 0")
plt.xlabel("t-SNE feature 1")
plt.show()

利用 t-SNE 找到的两个分量绘制 digits 数据集的散点图
在这里插入图片描述

t-SNE 的结果非常棒。所有类别都被明确分开。数字 1 和 9 被分成几块,但大多数类别都 形成一个密集的组。要记住,这种方法并不知道类别标签:它完全是无监督的。但它能够 找到数据的一种二维表示,仅根据原始空间中数据点之间的靠近程度就能够将各个类别明 确分开。
t-SNE 算法有一些调节参数,虽然默认参数的效果通常就很好。你可以尝试修改 perplexity 和 early_exaggeration,但作用一般很小。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值