机器学习中的嵌入:使复杂数据变得简单

已发表: 2022-03-11

即使对于经验丰富的数据科学家来说,使用非数值数据也很困难。 典型的机器学习模型期望其特征是数字,而不是单词、电子邮件、网站页面、列表、图表或概率分布。 为了有用,必须首先将数据转换为向量空间。 但是怎么做?

一种流行的方法是将非数字特征视为 categorical 。 如果类别的数量很少(例如,如果数据表明一个专业或一个国家),这可能会很有效。 但是,如果我们尝试将此方法应用于电子邮件,我们可能会获得与样本一样多的类别。 没有两封电子邮件完全相同,因此这种方法毫无用处。

另一种方法是定义数据样本之间的距离,这个函数告诉我们任意两个样本有多接近。 或者我们可以定义一个相似性度量,它会给我们相同的信息,除了两个接近的样本之间的距离很小而相似性很大。 计算所有数据样本之间的距离(相似度)会给我们一个距离(或相似度)矩阵。 这是我们可以使用的数字数据。

但是,这些数据的维度与样本的数量一样多,如果我们想将其用作特征(参见维度诅咒)或将其可视化(虽然一个图甚至可以处理 6D,但我还没有),这通常不是很好查看 100D 图)。 我们能否将维度的数量减少到合理的数量?

答案是肯定的! 这就是我们嵌入的目的。

什么是嵌入以及为什么要使用它?

嵌入是高维数据的低维表示。 通常,嵌入不会捕获原始数据中包含的所有信息。 然而,一个好的嵌入将足以解决手头的问题。

存在许多针对特定数据结构量身定制的嵌入。 例如,您可能听说过用于文本数据的 word2vec,或用于形状图像数据的傅立叶描述符。 相反,我们将讨论如何将嵌入应用于可以定义距离或相似性度量的任何数据。 只要我们可以计算距离矩阵,数据的性质就完全无关紧要了。 无论是电子邮件、列表、树还是网页,它的工作原理都是一样的。

在本文中,我们将向您介绍不同类型的嵌入,并讨论一些流行的嵌入是如何工作的,以及我们如何使用嵌入来解决涉及复杂数据的实际问题。 我们还将介绍这种方法的优缺点,以及一些替代方法。 是的,有些问题可以通过其他方式更好地解决,但不幸的是,机器学习没有灵丹妙药。

让我们开始吧。

嵌入如何工作

所有嵌入都试图降低数据的维度,同时保留数据中的“基本”信息,但每个嵌入都以自己的方式进行。 在这里,我们将介绍一些可以应用于距离或相似度矩阵的流行嵌入。

我们甚至不会尝试覆盖所有嵌入。 至少有十几个众所周知的嵌入可以做到这一点,还有更多鲜为人知的嵌入及其变体。 他们每个人都有自己的方法,优点和缺点。

如果您想看看还有哪些其他嵌入,您可以从这里开始:

  • Scikit-learn 用户指南
  • 统计学习的要素(第二版),第 14 章

距离矩阵

让我们简要介绍一下距离矩阵。 为数据找到合适的距离需要对问题有很好的理解,需要一些数学知识,有时还需要运气。 在本文描述的方法中,这可能是影响项目整体成功或失败的最重要因素。

您还应该牢记一些技术细节。 许多嵌入算法会假设距离(或相异)矩阵 $\textbf{D}$ 在其对角线上有零并且是对称的。 如果它不是对称的,我们可以使用 $(\textbf{D} + \textbf{D}^T) / 2$ 代替。 使用核技巧的算法还将假设距离是一个度量,这意味着三角不等式成立:

\[\forall a, b, c \;\; d(a,c) \leq d(a,b) + d(b,c)\]

此外,如果算法需要相似度矩阵,我们可以应用任何单调递减函数将距离矩阵转换为相似度矩阵:例如,$\exp -x$。

主成分分析 (PCA)

主成分分析(PCA)可能是迄今为止使用最广泛的嵌入。 这个想法很简单:找到最大化捕获方差或(等效地)最小化二次重建误差的特征的线性变换

具体来说,让特征是一个样本矩阵 $\textbf{X} \in \mathbb{R}^{n \times p}$ 有 $n$ 个特征和 $p$ 个维度。 为简单起见,我们假设数据样本均值为零。 我们可以通过将 $\textbf{X}$ 乘以正交矩阵 $\textbf{V}_q \in \mathbb{R}^{p \times q}$ 将维数从 $p$ 减少到 $q$ :

\[\hat{\textbf{X}} = \textbf{X} \textbf{V}_q\]

那么,$\hat{\textbf{X}} \in \mathbb{R}^{n \times q}$ 将是新的特征集。 要将新特征映射回原始空间(此操作称为重建),我们只需将其再次乘以 $\textbf{V}_q^T$。

现在,我们要找到最小化重构误差的矩阵 $\textbf{V}_q$:

\[\min_{\textbf{V}_q} ||\textbf{X}\textbf{V}_q\textbf{V}_q^T - \textbf{X}||^2\]

矩阵$\textbf{V}_q$ 的列称为主成分方向,$\hat{\textbf{X}}$ 的列称为主成分。 在数值上,我们可以通过对 $\textbf{X}$ 应用 SVD 分解来找到 $\textbf{V}_q$,尽管还有其他同样有效的方法可以做到这一点。

PCA 可以直接应用于数值特征。 或者,如果我们的特征是非数值的,我们可以将其应用于距离或相似度矩阵。

如果你使用 Python,PCA 是在 scikit-learn 中实现的。

这种方法的优点是计算速度快,并且对数据中的噪声具有很强的鲁棒性。

缺点是它只能捕获线性结构,因此原始数据中包含的非线性信息很可能会丢失。

内核 PCA

内核 PCA 是 PCA 的非线性版本。 这个想法是使用内核技巧,如果您熟悉支持向量机 SVM,您可能听说过。

具体来说,有几种不同的方法来计算 PCA。 其中之一是计算 gram 矩阵 $\textbf{X} \textbf{X}^T \in \mathbb{R}^{n \times n}$ 的双中心版本的特征分解。 现在,如果我们为我们的数据计算一个核矩阵$\textbf{K} \in \mathbb{R}^{n \times n}$,Kernel PCA 将把它当作一个 gram 矩阵来查找主成分。

令 $x_i$, $i \in {1,..,n}$ 为特征样本。 核矩阵由核函数 $K(x_i,x_j)=\langle \phi(x_i),\phi(x_j) \rangle$ 定义。

一个流行的选择是径向内核:

\[K(x_i,x_j)=\exp -\gamma \cdot d(x_i,x_j)\]

其中 $d$ 是距离函数。

内核 PCA 要求我们指定距离。 例如,对于数值特征,我们可以使用欧几里德距离:$d(x_i,x_j)=\vert\vert x_i-x_j \vert \vert ^2$。

对于非数字特征,我们可能需要发挥创造力。 要记住的一件事是,该算法假设我们的距离是一个度量。

如果你使用 Python,Kernel PCA 是在 scikit-learn 中实现的。

Kernel PCA 方法的优点是它可以捕获非线性数据结构。

缺点是对数据中的噪声敏感,距离和核函数的选择会对结果产生很大影响。

多维缩放 (MDS)

多维缩放(MDS)试图在全局范围内保持样本之间的距离。 这个想法非常直观,并且适用于距离矩阵。

具体来说,给定特征样本 $x_i$、$i \in {1,..,n}$ 和距离函数 $d$,我们计算新的特征样本 $z_i \in \mathbb{R}^{q}$, $i \in {1,..,n}$ 通过最小化应力函数

\[\min_{z_1,..,z_n} \sum_{1 \leq i < j \leq n} (d(x_i, x_j) - ||z_i - z_j||)^2\]

如果你使用 Python,MDS 是在 scikit-learn 中实现的。 但是,scikit-learn 不支持样本外点的转换,如果我们想将嵌入与回归或分类模型结合使用,这可能会很不方便。 但是,原则上是可以的。

MDS的优点是它的思想与我们的框架完全吻合,并且不受数据中噪声的影响。

缺点是它在 scikit-learn 中的实现很慢,不支持样本外转换。

用例:货件追踪

一个热带小岛上的一些定居点已经开发了包裹运输服务,以满足当地旅游业的需求。 其中一个定居点的商人决定采取行动以在竞争中获得优势,因此他建立了一个卫星监控系统,跟踪岛上所有的包裹运输。 收集到数据后,商家打电话给数据科学家(就是我们!)帮助他回答以下问题:我们能否预测当前正在运送的包裹的目的地?

该数据集包含有关 200 个跟踪货物的信息。 对于每个跟踪的货物,都有一个 (x,y) 坐标列表,表示发现包裹的所有位置,通常在 20 到 50 个观察值之间。 下图显示了这些数据的外观。

用例:货件追踪

这些数据看起来很麻烦——实际上是两种不同的麻烦。

第一个问题是我们处理的数据是高维的。 例如,如果在 50 个位置发现每个包裹,我们的数据将有 100 个维度——与您处理的 200 个样本相比,这听起来很多。

第二个问题:不同的运输路线实际上有不同数量的观察,因此我们不能简单地将列表与坐标堆叠以以表格形式表示数据(即使它们有,这仍然没有意义)。

商人不耐烦地用手指敲着桌子,数据科学家努力不表现出任何恐慌的迹象。

这就是距离矩阵和嵌入会派上用场的地方。 我们只需要找到一种方法来比较两条运输路线。 Frechet距离似乎是一个合理的选择。 通过距离,我们可以计算距离矩阵。

注意:此步骤可能需要一段时间。 我们需要计算 $O(n^2)$ 距离,每个距离都有 $O(k^2)$ 次迭代,其中 $n$ 是样本数,$k$ 是一个样本中的观察数。 有效地编写距离函数是关键。 例如,在 Python 中,您可以使用 numba 将这种计算加速很多倍。

可视化嵌入

现在,我们可以使用嵌入将维数从 200 减少到只有几个。 我们可以清楚地看到,只有几条贸易路线,所以我们可能希望即使在二维或三个维度上也能找到数据的良好表示。 我们将使用之前讨论过的嵌入:PCA、Kernel PCA 和 MDS。

在下图中,您可以看到标记的路线数据(为了演示而给出)及其通过 2D 和 3D 嵌入的表示(从左到右)。 标记的数据标记了由六条贸易路线连接的四个贸易站。 六条贸易路线中有两条是双向的,总共构成八个货运组(6+2)。 如您所见,我们通过 3D 嵌入对所有八个货运组进行了非常清晰的区分。

可视化嵌入

这是一个好的开始。

模型管道中的嵌入

现在,我们准备好训练嵌入了。 虽然 MDS 显示出最好的结果,但它相当慢; 此外,scikit-learn 的实现不支持样本外转换。 这对研究来说不是问题,但它可以用于生产,所以我们将使用 Kernel PCA 代替。 对于核 PCA,我们不应该忘记事先将径向核应用于距离矩阵。

你如何选择输出维度的数量? 分析表明,即使是 3D 也可以。 为了安全起见,不要遗漏任何重要信息,我们将嵌入输出设置为 10D。 为了获得最佳性能,可以将输出维度的数量设置为模型超参数,然后通过交叉验证进行调整。

因此,我们将拥有 10 个数字特征,我们可以将它们用作几乎任何分类模型的输入。 一个线性模型和一个非线性模型怎么样:比如逻辑回归和梯度提升? 为了比较,让我们也使用这两个模型以全距离矩阵作为输入。 最重要的是,让我们也测试 SVM(SVM 被设计为直接使用距离矩阵,因此不需要嵌入)。

测试集上的模型准确度如下图所示(生成了 10 个训练和测试数据集,因此我们可以估计模型的方差):

  • Gradient Boosting与嵌入(KernelPCA+GB)配对获得第一名。 它在没有嵌入 (GB) 的情况下优于梯度提升。 在这里,Kernel PCA 被证明是有用的。
  • 逻辑回归没问题。 有趣的是,没有嵌入 (LR) 的逻辑回归比嵌入 (KernelPCA+LR) 做得更好。 这并不完全出乎意料。 线性模型不是很灵活,但相对难以过拟合。 在这里,嵌入造成的信息丢失似乎超过了较小输入维度的好处。
  • 最后但同样重要的是, SVM也表现良好,尽管该模型的方差非常显着。

模型精度

模型精度

此用例的 Python 代码可在 GitHub 上找到。

结论

我们已经解释了嵌入是什么,并演示了如何将它们与距离矩阵结合使用来解决实际问题。 判决时间:

嵌入是数据科学家应该使用的东西吗? 让我们来看看故事的两面。

使用嵌入的优缺点

优点:

  • 这种方法允许我们使用不寻常或复杂的数据结构,只要你能定义一个距离——只要有一定程度的知识、想象力和运气——你通常可以。
  • 输出是低维数值数据,您可以轻松地对其进行分析、聚类或用作几乎所有机器学习模型的模型特征。

缺点:

  • 使用这种方法,我们必然会丢失一些信息:

    • 在第一步中,当我们用相似度矩阵替换原始数据时
    • 在第二步中,当我们使用嵌入来降低维度时
  • 根据数据和距离函数,距离矩阵的计算可能很耗时。 这可以通过有效写入的距离函数来缓解。
  • 一些嵌入对数据中的噪声非常敏感。 这可以通过额外的数据清理来缓解。
  • 一些嵌入对其超参数的选择很敏感。 这可以通过仔细分析或超参数调整来缓解。

替代方案:为什么不使用……?

  • 为什么不直接在数据上使用嵌入,而不是距离矩阵?
    如果您知道可以直接有效地对数据进行编码的嵌入,请务必使用它。 问题是它并不总是存在。
  • 为什么不在距离矩阵上使用聚类?
    如果你唯一的目标是分割你的数据集,那么这样做是完全可以的。 一些聚类方法也利用嵌入(例如,光谱聚类)。 如果您想了解更多信息,这里是关于集群化的教程。
  • 为什么不直接使用距离矩阵作为特征?
    距离矩阵的大小为 $(n_{samples}, n_{samples})$。 并非所有模型都可以有效地处理它——有些可能过拟合,有些可能拟合缓慢,有些可能完全无法拟合。 具有低方差的模型在这里是一个不错的选择,例如线性和/或正则化模型。
  • 为什么不直接使用带距离矩阵的 SVM?
    SVM 是一个很棒的模型,在我们的用例中表现良好。 但是,有一些警告。 首先,如果我们想添加其他特征(可能只是简单的数字),我们将无法直接做到这一点。 我们必须将它们合并到我们的相似性矩阵中,并且可能会丢失一些有价值的信息。 其次,与 SVM 一样好,另一种模型可能更适合您的特定问题。
  • 为什么不直接使用深度学习?
    的确,对于任何问题,只要搜索足够长的时间,就能找到合适的神经网络。 但请记住,寻找、训练、验证和部署这个神经网络的过程不一定是一个简单的过程。 所以,一如既往,用你最好的判断。

一句话

如果您碰巧处理复杂的非数值数据,尤其是当您无法将数据直接转换为向量空间并且希望为模型提供低维输入时,嵌入与距离矩阵的结合是一个非常有用的工具。