网站建设风险的特征,平面设计公司职位,建材采购网,好玩的传奇关键词#xff1a; Uniform Manifold Approximation and Projection (UMAP)#xff1a;均匀流形近似与投影
一、说明
对于降维#xff0c;首先看数据集是否线性#xff0c;如果是线性的用pca降维#xff1b;如果是非线性数据#xff0c;t-SNE或者UMAP#xff0c;本文针…关键词 Uniform Manifold Approximation and Projection (UMAP)均匀流形近似与投影
一、说明
对于降维首先看数据集是否线性如果是线性的用pca降维如果是非线性数据t-SNE或者UMAP本文针对UMAP的实验代码进行记录但没有说UMAP的原理原理在其它文档论述。
二、UMAP的基本概念
2.1 首先看什么是流形
流形manifold是一种数学概念它描述了在局部看起来像欧几里得空间的拓扑空间。换句话说流形是一个可以在局部范围内近似为欧几里得空间的空间。流形在几何、拓扑学、微分几何以及物理学中有广泛的应用。流形的基本概念包括连续性、局部坐标转移性和可微性常见的例子有闭合曲面和克莱因瓶等。 一般来说微分几何是建立在流形理论上的学习这方面的理论可以参照微分几何相关书籍。
2.2 UMAP
均匀流形近似与投影 (UMAP) 是一种降维技术类似于 t-SNE可用于可视化也可用于一般的非线性降维。该算法基于以下三个关于数据的假设
数据在黎曼流形上均匀分布 黎曼度量是局部常数或可以近似为局部常数 流形是局部连通的。
基于这些假设可以用模糊拓扑结构对流形进行建模。通过寻找具有最接近等效模糊拓扑结构的数据低维投影来找到嵌入。
2.3 UMAP 安装
在conda上安装umap
conda install -c conda-forge umap-learn在pip安装
pip install umap-learn三、基本 UMAP 参数
UMAP 是一种相当灵活的非线性降维算法。它旨在学习数据的流形结构并找到一个能够保留该流形基本拓扑结构的低维嵌入。在本笔记中我们将生成一些可可视化的四维数据演示如何使用 UMAP 提供其二维表示然后研究各种 UMAP 参数如何影响最终的嵌入。本文档基于 Philippe Rivière 为 visionscarto.net 撰写的研究成果。
首先我们需要一些基础库。首先numpy我们需要 来进行基本的数组操作。由于我们要可视化结果因此需要matplotlib和seaborn。最后我们需要 umap来进行维度缩减本身。
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import seaborn as sns
import umap
%matplotlib inline
sns.set(stylewhite, contextposter, rc{figure.figsize:(14,10)})接下来我们需要一些数据来嵌入到低维表示中。为了使四维数据“可视化”我们将从一个四维立方体中均匀随机地生成数据以便我们可以将样本解释为指定颜色和透明度的 (R,G,B,a) 值的元组。这样当我们绘制低维表示时每个点都可以根据其四维值进行着色。为此我们可以使用numpy。为了保持一致性我们将固定一个随机种子。
np.random.seed(42)
data np.random.rand(800, 4)现在我们需要找到数据的低维表示。正如基础用法文档中所述我们可以通过 在对象fit_transform()上使用方法来做到这一点UMAP。
fit umap.UMAP()
%time u fit.fit_transform(data)CPU times: user 7.73 s, sys: 211 ms, total: 7.94 s Wall time: 6.8 s 结果值u是数据的二维表示。我们可以用matplotlib绘制散点图来可视化结果u。我们可以使用源数据中关联的四维颜色为散点图的每个点着色。
plt.scatter(u[:,0], u[:,1], cdata)
plt.title(UMAP embedding of random colours);正如你所见结果是数据被放置在二维空间中使得四维空间中相邻的点即颜色相似的点保持紧密相连。由于我们在颜色立方体中随机抽取了一些点因此在颜色空间中这些随机点恰好聚集在一起从而产生了一定程度的诱导结构。
UMAP 有几个超参数会对最终的嵌入产生重大影响。在本笔记中我们将介绍其中四个主要参数
n_neighbors
min_dist
n_components
metric每个参数都有不同的效果我们将依次进行讨论。为了简化探索我们首先编写一个简短的效用函数该函数可以在给定一组参数选择的情况下使用 UMAP 拟合数据并绘制结果图。
def draw_umap(n_neighbors15, min_dist0.1, n_components2, metriceuclidean, title):fit umap.UMAP(n_neighborsn_neighbors,min_distmin_dist,n_componentsn_components,metricmetric)u fit.fit_transform(data);fig plt.figure()if n_components 1:ax fig.add_subplot(111)ax.scatter(u[:,0], range(len(u)), cdata)if n_components 2:ax fig.add_subplot(111)ax.scatter(u[:,0], u[:,1], cdata)if n_components 3:ax fig.add_subplot(111, projection3d)ax.scatter(u[:,0], u[:,1], u[:,2], cdata, s100)plt.title(title, fontsize18)
n_neighbors 此参数控制 UMAP 如何平衡数据的局部结构与全局结构。它通过限制 UMAP 在尝试学习数据流形结构时所关注的局部邻域的大小来实现这一点。这意味着较低的 值n_neighbors 将迫使 UMAP 专注于非常局部的结构可能会损害全局而较大的 值将迫使 UMAP 在估计数据的流形结构时关注每个点的更大邻域从而为了获取更广泛的数据而丢失精细的细节结构。
在实践中我们可以通过使用一系列n_neighbors值来拟合数据集从而看到这一点。UMAP 的默认值n_neighbors 如上所述为 15但我们将研究从 2流形的局部视图到 200数据的四分之一范围内的值。
for n in (2, 5, 10, 20, 50, 100, 200):draw_umap(n_neighborsn, titlen_neighbors {}.format(n))当值为 时n_neighbors2我们可以看到 UMAP 仅仅将一些小的链粘合在一起但由于视角狭窄/局部无法看到它们是如何连接的。它还留下了许多不同的组成部分甚至是单点。这表明从细节的角度来看数据在整个空间中非常不连贯且分散。
随着n_neighborsUMAP 的增加它能够更好地洞察数据的整体结构将更多组件粘合在一起并更好地覆盖数据的整体结构。到这个阶段 n_neighbors20我们对数据有了相当好的整体视图展示了各种颜色在整个数据集中是如何相互关联的。
随着n_neighbors数据的整体结构越来越受到关注。结果虽然 n_neighbors200图中能够很好地捕捉到整体结构蓝色、绿色和红色高亮度与低亮度但却丢失了一些更精细的局部结构单个颜色不再必然与其最接近的颜色匹配。
这种效果很好地体现了所提供的局部/全局权衡 n_neighbors。
min_dist
该min_dist参数控制 UMAP 将点打包的紧密程度。它实际上规定了低维表示中允许点之间的最小距离。这意味着较低的 值min_dist将导致嵌入更加块状。如果您对聚类或更精细的拓扑结构感兴趣这将非常有用。较大的 值 min_dist将阻止 UMAP 将点打包在一起而是专注于保留大致的拓扑结构。
min_dist如上所述的默认值为0.1。我们将查看从 0.0 到 0.99 的值范围。
for d in (0.0, 0.1, 0.25, 0.5, 0.8, 0.99):draw_umap(min_distd, titlemin_dist {}.format(d))这里我们看到min_dist0.0UMAP 能够找到数据中较小的连通分量、团块和字符串并在生成的嵌入中强调这些特征。随着 的min_dist增加这些结构被分解成更柔和、更通用的特征从而在损失更详细的拓扑结构的情况下提供更好的数据总体视图。
n_components
scikit-learn与许多降维算法一样 UMAP 提供了一个n_components参数选项允许用户确定我们将数据嵌入到的降维空间的维数。与其他一些可视化算法例如 t-SNE不同UMAP 在嵌入维度上具有良好的扩展性因此您不仅可以将其用于二维或三维可视化还可以将其用于其他领域。
为了演示的目的以便我们可以看到参数的效果我们将只研究一维和三维嵌入我们希望将其可视化。
首先我们将设置n_components为 1强制 UMAP 将数据嵌入到一条线中。为了便于可视化我们将在 y 轴上随机分布数据以便在点之间提供一定的分隔。
draw_umap(n_components1, titlen_components 1)现在我们来尝试一下n_components3。为了实现可视化我们将利用的matplotlib基本三维绘图。
draw_umap(n_components3, titlen_components 3)在这里我们可以看到有了更多的工作维度UMAP 可以更轻松地以尊重数据拓扑结构的方式分离出颜色。
如上所述实际上没有必要止步于n_components3。如果您对基于密度的聚类或其他机器学习技术感兴趣那么选择一个更大的嵌入维度例如 10 或 50并使其更接近数据所在的底层流形的维度可能会有所帮助。
metric度量
我们将在本笔记本中考虑的最后一个 UMAP 参数是 metric参数。它控制如何在输入数据的环境空间中计算距离。默认情况下UMAP 支持多种指标包括
闵可夫斯基风格度量
欧几里得
曼哈顿
切比雪夫
闵可夫斯基
其他空间指标
堪培拉
布雷柯蒂斯
半正矢
规范化空间度量
马哈拉诺比斯
明科夫斯基
塞克利德
角度和相关性指标
余弦
相关性
二进制数据的指标
汉明 雅卡德 骰子 罗素·拉奥 库尔辛斯基 罗杰斯塔尼莫托 索卡尔米切纳 索卡尔斯尼斯 圣诞节
四、预先计算
以上所有指标都假设你的输入数据是某个 N 维空间中的“原始”数据。有时你已经计算了点之间的成对距离并且输入数据是一个距离/相似度矩阵。在这种情况下你可以执行以下操作。
UMAP(metricprecomputed).fit_transform(distance matrix)其中任何一个都可以通过设置。metricmetriccosine’来指定例如使用余弦距离作为您将使用的度量
然而UMAP 提供的远不止这些——它支持自定义用户指标只要这些指标能够nopython通过 numba 编译即可。在本笔记中我们将研究此类自定义指标。要定义此类指标我们需要 numba……
import numba对于我们的第一个自定义指标我们将距离定义为红色通道中差异的绝对值。
numba.njit()
def red_channel_dist(a,b):return np.abs(a[0] - b[0])为了更具冒险精神进行一些色彩空间转换会很有用——为了简单起见我们只需使用 HSL 公式从 (R,G,B) 元组中提取色调、饱和度和亮度。
numba.njit()
def hue(r, g, b):cmax max(r, g, b)cmin min(r, g, b)delta cmax - cminif cmax r:return ((g - b) / delta) % 6elif cmax g:return ((b - r) / delta) 2else:return ((r - g) / delta) 4numba.njit()
def lightness(r, g, b):cmax max(r, g, b)cmin min(r, g, b)return (cmax cmin) / 2.0numba.njit()
def saturation(r, g, b):cmax max(r, g, b)cmin min(r, g, b)chroma cmax - cminlight lightness(r, g, b)if light 1:return 0else:return chroma / (1 - abs(2*light - 1))有了这些我们可以定义三个额外的距离。第一个简单地测量色调的差异第二个测量饱和度和亮度组合空间中的欧氏距离第三个测量完整 HSL 空间中的距离。
numba.njit()
def hue_dist(a, b):diff (hue(a[0], a[1], a[2]) - hue(b[0], b[1], b[2])) % 6if diff 0:return diff 6else:return diffnumba.njit()
def sl_dist(a, b):a_sat saturation(a[0], a[1], a[2])b_sat saturation(b[0], b[1], b[2])a_light lightness(a[0], a[1], a[2])b_light lightness(b[0], b[1], b[2])return (a_sat - b_sat)**2 (a_light - b_light)**2numba.njit()
def hsl_dist(a, b):a_sat saturation(a[0], a[1], a[2])b_sat saturation(b[0], b[1], b[2])a_light lightness(a[0], a[1], a[2])b_light lightness(b[0], b[1], b[2])a_hue hue(a[0], a[1], a[2])b_hue hue(b[0], b[1], b[2])return (a_sat - b_sat)**2 (a_light - b_light)**2 (((a_hue - b_hue) % 6) / 6.0)有了这些自定义指标我们就可以让 UMAP 使用这些指标来嵌入数据以测量输入数据点之间的距离。需要注意的是这numba为我们定义距离函数提供了极大的灵活性。尽管如此即使使用这些自定义函数我们仍然能够保持 UMAP 所期望的高性能。
for m in (euclidean, red_channel_dist, sl_dist, hue_dist, hsl_dist):name m if type(m) is str else m.__name__draw_umap(n_components2, metricm, titlemetric {}.format(name))在这里我们可以清楚地看到这些指标的效果。纯红色通道正确地将数据视为位于一维流形上色调指标将数据解释为位于一个圆圈内而 HSL 指标则根据饱和度和亮度使圆圈变胖。这合理地证明了 UMAP 在理解数据底层拓扑结构以及找到该拓扑结构的合适低维表示方面的强大功能和灵活性。