UMAP 是一种通用的流形学习和降维算法。 它旨在与 scikit-learn 兼容,使用相同的 API 并能够添加到 sklearn 管道中。 如果您已经熟悉 sklearn,您应该能够使用 UMAP 作为 t-SNE 和其他降维类的替代品。 如果您对 sklearn 不太熟悉,本教程将引导您了解使用 UMAP 转换和可视化数据的基础知识。
首先,我们需要导入一堆有用的工具。 我们显然需要 numpy,但我们将使用 sklearn 中可用的一些数据集以及 train_test_split
函数来划分数据。 最后,我们需要一些绘图工具(matplotlib 和 seaborn)来帮助我们可视化 UMAP 的结果,而 pandas 可以让这更容易一些。
import numpy as np
from sklearn.datasets import load_digits
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
%matplotlib inline # Notebook需要,pycharm不需要
sns.set(style='white', context='notebook', rc={'figure.figsize':(14,10)})
下一步是获取一些可以使用的数据。 为了让我们更容易理解,我们将从企鹅数据集开始。 它并不能很好地代表真实数据的样子,但它的点数和特征数都很小,可以让我们了解降维的作用。
penguins = pd.read_csv("https://github.com/allisonhorst/palmerpenguins/raw/5b5891f01b52ae26ad8cb9755ec93672f49328a8/data/penguins_size.csv")
print(penguins.head())
上面代码有时会报错如下:
可以将上述代码换成如下代码读取企鹅数据集:
import pandas as pd
import io
import requests
url="https://github.com/allisonhorst/palmerpenguins/raw/5b5891f01b52ae26ad8cb9755ec93672f49328a8/data/penguins_size.csv"
s=requests.get(url).content
penguins=pd.read_csv(io.StringIO(s.decode('utf-8')))
print(penguins.head())
由于这是出于演示目的,我们将去掉数据中的 NA; 在现实世界中,人们希望更加注意正确处理丢失的数据。
penguins=penguins.drop('Unnamed: 0',axis=1)
penguins = penguins.dropna()
print(penguins.species_short.value_counts())
有关数据集本身的更多详细信息,请参阅 github 存储库。 它包括三种企鹅的喙(culmen)和鳍状肢和重量的测量值,以及有关企鹅的一些其他元数据。 我们总共测量了 334 只不同的企鹅。 可视化这些数据有点棘手,因为我们不能轻松地绘制 4 维。 幸运的是,四个并不是一个很大的数字,所以我们可以通过一个成对的特征散点图矩阵来了解发生了什么。 Seaborn 让这一切变得简单。
#hue:针对某一字段进行分类
sns.pairplot(penguins, hue='species_short')
plt.show()
通过给出数据的所有 2D 视图,这让我们对数据的外观有了一些了解。 四个维度足够低,我们可以(某种程度上)重建全维度数据在我们脑海中的样子。 现在我们有点知道我们在看什么,问题是像 UMAP 这样的降维技术可以为我们做什么? 通过以尽可能多地保留数据结构的方式减少维度,我们可以获得数据的可视化表示,使我们能够“看到”数据及其结构,并开始对数据本身有一些直觉。
要使用 UMAP 完成这项任务,我们首先需要构造一个 UMAP 对象来为我们完成这项工作。 这就像实例化类一样简单。 因此,让我们导入 umap 库并执行此操作。
首先在运行代码环境中安装umap:
pip install umap-learn -i https://mirrors.ustc.edu.cn/pypi/web/simple
导入并实例化umap:
import umap as umap
reducer = umap.UMAP()
在我们可以对数据进行任何工作之前,将其清理一下会有所帮助。 我们不需要 NA,我们只需要测量列,并且由于测量是在完全不同的尺度上,因此将每个特征转换为 z 分数(与平均值的标准偏差数)以进行可比性会很有帮助。
penguin_data = penguins[
[
"culmen_length_mm",
"culmen_depth_mm",
"flipper_length_mm",
"body_mass_g",
]
].values
scaled_penguin_data = StandardScaler().fit_transform(penguin_data)
现在我们需要训练我们的减速器,让它了解流形。 对于这个 UMAP 遵循 sklearn API 并有一个方法 fit
,我们传递希望模型学习的数据。我们将希望减少我们使用的数据表示,所以调用 fit_transform
方法(首先调用 fit
然后将转换后的数据作为 numpy 数组返回的)。
embedding = reducer.fit_transform(scaled_penguin_data)
print(embedding.shape) # (334, 2)
结果是一个包含 334 个样本的数组,但只有两个特征列(而不是我们开始时的四个)。 这是因为默认情况下,UMAP 会缩减为 2D。 数组的每一行都是对应企鹅的二维表示。 因此,我们可以将嵌入绘制为标准散点图和目标数组的颜色(因为它适用于与原始数据顺序相同的转换数据)。
plt.scatter(
embedding[:, 0],
embedding[:, 1],
c=[sns.color_palette()[x] for x in penguins.species_short.map({"Adelie":0, "Chinstrap":1, "Gentoo":2})])
plt.gca().set_aspect('equal', 'datalim') # 用于设置轴缩放的方面,即y-unit与x-unit的比率
plt.title('UMAP projection of the Penguin dataset', fontsize=24)
plt.show()
这在捕获数据结构方面很有用,从散点图矩阵可以看出,这是相对准确的。 当然,我们至少从散点图矩阵中学到了这么多——我们可以这样做,因为我们只有四个不同的维度要分析。 如果我们有更多维度的数据,散点图矩阵很快就会变得难以绘制,并且更难以解释。
[1] UMAP官方文档