高维数据中的最近邻居?


163

几天前,我已经问了一个问题,问题是如何找到给定向量的最近邻居。我的向量现在是21维,在继续下一步之前,因为我既不是机器学习也不是数学领域的专家,所以我开始问自己一些基本问题:

  • 欧几里得距离是一个很好的度量标准,可以用来首先找到最近的邻居?如果没有,我有什么选择?
  • 另外,如何确定用于确定k个邻居的正确阈值?是否可以进行一些分析以找出该值?
  • 以前,有人建议我使用kd-Trees,但Wikipedia页面上明确指出,对于高维,kd-Tree几乎等同于蛮力搜索。在那种情况下,有效地找到一百万个点数据集中的最近邻居的最佳方法是什么?

有人可以澄清上面的一些(或全部)问题吗?


尝试在metaoptimize.com上提问
pajton

4
“高维”对于某些人和某些数据为20,对于其他人为50或100或1000。如果可以的话,请提供数字,例如“我用xx完成了暗21、1000000个数据点”。
denis

kD-Tree一次沿一维将数据分成两部分。如果您有20个维度,并且只有1M个数据点,则将得到大约1层树-其中的层表示在每个轴上均分开。由于没有真正的深度,因此您不会从忽略树的分支中受益。即使将其实现为二叉树,也不要将其视为二叉树,而更像是四叉树,八叉树等。
phkahler

@denis,是希格斯数据集的“ dim 21,1000000个数据点”吗?
尼克,

1
这是下载希格斯数据集的链接。1100万个观测值具有28个属性。最后一列是标签:1表示信号,零表示噪声。archive.ics.uci.edu/ml/datasets/HIGGS
尼克

Answers:


179

我目前正在研究此类问题-分类,最近邻居搜索-以获取音乐信息。

您可能对近似最近邻居ANN)算法。这个想法是让算法允许返回足够近的邻居(也许不是最近的邻居)。这样可以减少复杂性。您提到了kd-tree;那是一个例子。但是正如您所说,kd-tree在高维度上效果不佳。实际上,所有当前的索引技术(基于空间划分)都降级为对足够高的尺寸进行线性搜索[1] [2] [3]。

在最近提出的ANN算法中,也许最受欢迎的是局部敏感哈希Locality-Sensitive HashingLSH),它将高维空间中的一组点映射到一组bin中,即哈希表[1] [3]。但是与传统的哈希不同,对位置敏感的哈希将附近的点放置在同一容器中。

LSH具有一些巨大的优势。首先,它很简单。您只需计算数据库中所有点的哈希,然后根据它们创建一个哈希表。要进行查询,只需计算查询点的哈希值,然后从哈希表中检索同一bin中的所有点。

其次,有一个严格的理论支持其性能。可以看出,查询时间在数据库大小上是次线性的,即比线性搜索快。快多少取决于我们可以忍受的近似程度。

最后,LSH与的任何Lp规范兼容0 < p <= 2。因此,要回答第一个问题,您可以将LSH与欧几里得距离度量标准结合使用,或者将其与曼哈顿(L1)距离度量标准结合使用。汉明距离和余弦相似度也有变体。

Malcolm Slaney和Michael Casey在2008年为IEEE Signal Processing Magazine撰写了不错的综述[4]。

LSH似乎已在所有地方得到应用。您可能需要尝试一下。


[1] Datar,Indyk,Immorlica,Mirrokni,“基于p稳定分布的局部敏感散列方案”,2004年。

[2] Weber,Schek,Blott,“高维空间中相似性搜索方法的定量分析和性能研究”,1998年。

[3] Gionis,Indyk,Motwani,“通过散列在高维中进行相似性搜索”,1999年。

[4] Slaney,Casey,“对位置敏感的哈希,用于寻找最近的邻居”,2008年。


1
@Steve:谢谢你的答复。您对LSH实施有什么建议吗?我唯一看到的是麻省理工学院的一本书。还有其他软件包吗?
联想

1
除了那一个,不,我不认识其他人。我最终出于自己的特定目的用Python编写了自己的代码。本质上,每个哈希表都实现为Python字典d,其中d[k]是一个带key的bin kd[k]包含哈希为的所有点的标签k。然后,您只需要计算每个点的哈希值即可。参见式 [4]中的(1)或[1]中的第3节。
史蒂夫·乔阿

@Steve:谢谢您的帮助。我现在开始执行它。您是否对这种方法如何对大型数据集执行任何想法?
联想

1
另一个支持LSH的参考:在高维空间中比较最近的邻居算法,Hendra Gunadi,2011年。cs.anu.edu.au/student/projects/11S2/Reports
Oliver Coleman

1
@SteveTjoa:发现很难从视觉上把握关键字和嵌入式公式。由于您已经对LSH进行了重点介绍,因此我对其进行了补充。只有最好的意图。不过,请随时还原。毕竟是你的答案。:)
后悔者2013年

81

I.距离度量

首先,数据集中的要素(列)数量不是选择用于kNN的距离度量的因素。有很多针对这一问题的已发表研究,比较的通常依据是:

  • 数据的基本统计分布;

  • 构成数据的要素之间的关系(它们是独立的-即协方差矩阵是什么样子); 和

  • 从中获取数据的坐标空间。

如果您不了解数据采样的分布,请至少进行一项(有据可查且详尽的)研究得出结论,欧几里德距离是最佳选择。

YEuclidean度量标准用于大规模Web推荐引擎以及当前的学术研究中。欧几里得距离计算的距离具有直观的含义和计算范围,即,无论两点是二维空间还是22维空间,欧几里德距离的计算方式都是相同的。

它对我来说只有几次失败,在每种情况下,欧几里得距离都失败了,因为基础(笛卡尔)坐标系是一个糟糕的选择。而且您通常会认识到这一点,因为例如路径长度(距离)不再是累加的,例如,当公制空间是国际象棋棋盘时,曼哈顿距离要比欧几里得更好,同样,当公制空间是地球并且您的距离是反距离时-洲际飞行,适合于极坐标系的距离度量是一个好主意(例如,伦敦到维也纳为2.5小时,维也纳到圣彼得堡为3小时,或多或少在同一方向,而伦敦到圣地圣彼得堡不是5.5小时,而是3小时多一点。)

但是,除了数据属于非笛卡尔坐标系的情况以外,距离度量的选择通常并不重要。(请参阅来自CS学生的博客文章,通过检查距离度量标准对kNN分类器的影响来比较多个距离度量标准-卡方得出最佳结果,但差异并不大;学术论文中有更全面的研究,比较研究最近邻的距离函数-马哈拉诺比斯(本质上是欧几里得,用尺寸协方差归一化)是本研究中最好的。

一个重要的条件:要使距离度量计算有意义,您必须 重新缩放您的数据-很少有可能建立kNN模型来生成准确的预测,而无需这样做。例如,如果您正在建立一个kNN模型来预测运动表现,并且您的期望变量是身高(cm),体重(kg),体脂(%)和静息脉动(每分钟心跳数),那么典型数据点可能看起来像这样:[180.4,66.1,11.3,71]。显然,距离计算将以身高为主导,而体脂百分比的贡献几乎可以忽略不计。换句话说,如果报告的数据不同,那么体重以克而不是千克为单位,那么原始值86.1将为86,100,这将对您的结果产生重大影响,而这正是您要做的不想。

X_new = (X_old - mu) / sigma


二。数据结构

如果您担心kd-tree结构的性能,Voronoi Tessellation是概念上简单的容器,但它将大大提高性能,并且比kd-Trees更好地扩展。

t

这不是持久保留kNN训练数据的最常见方法,尽管对此已充分记录了VT的应用以及由此带来的性能优势(例如,参见此Microsoft Research报告)。这样做的实际意义是,假设您使用的是“主流”语言(例如,在TIOBE Index中),那么您应该找到一个执行VT的库。我知道在Python和R中,每种语言都有多个选项(例如,在CRAN上提供R 的voronoi软件包

将VT用于kNN的工作方式如下:

从您的数据中随机选择w点-这是您的Voronoi中心。Voronoi单元封装了距离每个中心最近的所有相邻点。想象一下,如果您为每个Voronoi中心指定了不同的颜色,那么分配给给定中心的每个点都将涂上该颜色。只要您有足够的密度,这样做就能很好地显示每个Voronoi中心的边界(作为分隔两种颜色的边界)。

如何选择沃罗诺伊中心?我使用两个正交准则。随机选择w点后,为您的训练数据计算VT。接下来,检查分配给每个Voronoi中心的数据点数-这些值应大致相同(在整个数据空间中均采用统一的点密度)。在二维中,这将导致VT具有相同大小的图块,这是第一条规则,这是第二条规则。通过迭代选择w-使用w作为变量参数运行kNN算法,然后测量性能(通过查询VT返回预测所需的时间)。

因此,假设您有一百万个数据点.....如果这些点被保存在普通的2D数据结构或kd树中,则平均需要进行数百万次的距离计算 每个点您希望预测其响应变量的新数据点。当然,这些计算是在单个数据集上执行的。借助V / T,分两步对两个不同的数据群进行最近邻居搜索-首先对Voronoi中心进行搜索,然后在找到最近的中心后,单元内的点对应于搜索该中心以找到实际的最接近的邻居(通过连续的距离计算)。结合起来,这两个查找要比单个暴力查找快得多。这很容易看到:对于1M个数据点,假设您选择250个Voronoi中心来整理数据空间。平均每个Voronoi单元将拥有4,000个数据点。因此,您不必执行平均500,000次距离计算(强力),而是执行更少的操作,平均只需125 + 2,000。

三,计算结果(预测的响应变量)

根据一组kNN训练数据计算预测值有两个步骤。第一个是标识n或用于此计算的最近邻居的数量。第二个是如何加权他们对预测值的贡献

W / r / t是第一个组件,您可以通过解决优化问题(与最小二乘法最相似)来确定n的最佳值。那是理论;实际上,大多数人只使用n = 3。无论如何,很容易在一组测试实例(用于计算n = 1,n = 2,n = 3等)上运行kNN算法(以计算预测值),并将误差绘制为n的函数。如果您只是想让n成为一个合理的值,请再次使用n = 3。

第二部分是如何加权每个邻居的贡献(假设n> 1)。

最简单的加权技术是将每个邻居乘以一个加权系数,加权系数仅为1 /(dist * K),即从该邻居到测试实例的距离的倒数,通常乘以一些经验得出的常数K。不喜欢这种技术,因为它常常使最近的邻居过重(并同时使距离较远的邻居过轻);这样做的意义在于,给定的预测几乎可以完全取决于单个邻居,从而提高了算法对噪声的敏感度。

必须更好地加权的函数,实质上避免了这种限制的是高斯函数,在python中看起来像这样:

def weight_gauss(dist, sig=2.0) :
    return math.e**(-dist**2/(2*sig**2))

要使用kNN代码计算预测值,您需要确定要预测其响应变量的数据点的n个最近邻居(“测试实例”),然后为n个邻居中的每个邻居调用一次weight_gauss函数,该函数将返回每个邻居的权重,然后将其用作加权平均计算中该邻居的系数。


2
好答案!相对于我的经验而言全面而准确。
Ted Dunning

不错的答案,+ 1,我在这里添加了新的较新的答案,这样好吗?
gsamaras

1
“因此,假设您有一百万个数据点.....如果这些点被保存在普通的2D数据结构或kd-tree中,则对于每个其响应的新数据点平均要进行数百万个距离计算您希望预测的变量。” 不同意。可以证明,KD树O(sqrt(n))在2D中具有搜索复杂性。
Antoine

16

您所面临的被称为维咒。有时运行PCA或ICA之类的算法很有用以确保您确实需要全部21个维度,并可能找到一个线性变换,该变换可使您使用少于21个维度并获得大致相同的结果质量。

更新: 我在Rangayyan撰写的一本名为《生物医学信号处理》的书中遇到了它们(我希望我能正确记住它)。ICA并非微不足道的技术,但它是由芬兰的研究人员开发的,我认为它的Matlab代码可公开下载。PCA是一种使用更广泛的技术,我相信您应该能够找到它的R或其他软件实现。PCA通过迭代求解线性方程式来执行。我做这件事太久了,以至于还不记得如何做。=)

想法是将信号分解为独立的特征向量(实际上是离散的特征函数)及其特征值(在您的情况下为21)。每个特征值显示每个特征函数对每个测量的贡献量。如果特征值很小,则可以非常紧密地表示信号,而无需使用其相应的特征函数,这就是摆脱维数的方式。


+1谢谢。这是一个非常有趣的建议,很有意义。作为最后的要求,您是否熟悉任何动手教程(以python或R或其他语言),该教程介绍了如何以交互方式进行操作(我的意思是逐步解释整个过程)。从昨天开始,我已经阅读了一些文档,但是其中大多数似乎超出了我的理解。有什么建议?
联想

4
细化:ICA不是降维算法。它不知道如何对成分进行评分,因此不应该这样使用。
盖尔·瓦卢夸

12

最佳答案不错,但是很旧,所以我想加一个2016年的答案


如上所述,在高维空间中,维数的诅咒潜伏在拐角处,使得传统方法(例如流行的kd树)的速度与蛮力方法一样慢。结果,我们对“ 近似最近邻居搜索”(ANNS)产生了兴趣,这有助于提高准确性。您可以很好地近似精确的NN,并具有良好的可扩展性。


可能值得关注的热门话题:

  1. LSH的现代方法,例如Razenshteyn的方法。
  2. RKD森林FLANN中所述的随机kd树(RKD)的森林,或者我最近参与的kd-GeRaF的一部分
  3. LOPQ它代表局部优化的产品量化,如所描述这里。这与新的Babenko + Lemptitsky的方法非常相似。

您还可以检查我的相关答案:

  1. 两组高维点:在另一组中找到最近的邻居
  2. 比较不同数据结构上的最近邻居查询的运行时
  3. PCL kd-tree实施非常慢

8

要一一回答您的问题:

  • 不,欧氏距离在高维空间中是一个不好的指标。基本上在高维上,数据点之间存在很大差异。这减少了给定数据点与其最近和最远邻居之间的距离的相对差异。
  • 高维数据中有大量论文/研究,但大多数内容都需要大量的数学知识。
  • KD树不利于高维数据...一定要避免

这是一篇不错的论文,可以帮助您正确地开始工作。“ 什么时候在最近的邻居有意义?” 由Beyer等所有。

我使用尺寸为20K及以上的文本数据。如果您需要一些与文本相关的建议,我可能会为您提供帮助。


1
+1我正在打印该纸以供阅读。同时,您对如何找出最近的邻居有什么建议?如果距离度量和邻居本身的定义都存在缺陷,那么人们通常如何解决较高维度的问题,而他们希望基于特征向量进行近似匹配?有什么建议?
传奇

1
对于文本,我们经常使用余弦相似度。我本人正在进行文本分类,发现对于高维,带有线性内核的SVM似乎是最有效的。
BiGYaN 2011年

@BiGYaN您如何定义空间。我的意思是基于词向量或嵌入向量的包?
user3487667

@ user3487667,空格取决于您如何制定问题。我在谈论一个简单的单词袋模型。
BiGYAN

5

余弦相似度是比较高维向量的常用方法。请注意,由于它是相似性而不是距离,因此您要最大化它而不是最小化它。您还可以使用特定于域的方式来比较数据,例如,如果您的数据是DNA序列,则可以使用考虑到突变概率等的序列相似性。

使用的最近邻居的数量根据数据类型,噪声多少等而变化。没有通用规则,您只需尝试范围内的所有值即可找到最适合您的特定数据和问题的方法。人们有一个直观的认识,即数据越多,所需的邻居就越少。在假设条件下,您拥有所有可能的数据,则只需寻找单个最近邻居即可进行分类。

已知k最近邻方法在计算上很昂贵。这是人们转向支持向量机等其他算法的主要原因之一。


这是有趣的。您能否详细说明如何使用SVM?我认为k最近邻居更像是不受监督的,而SVM受监督。如果我错了,请纠正我。
传奇

2
两种方法都受到监督,因为您的训练数据使用正确的类进行了注释。如果仅具有特征向量,并且不知道它们所属的类,则不能使用kNN或SVM。无监督学习方法通​​常称为聚类算法。他们可以识别相似数据的组,但不能告诉您组的含义。
科林

谢谢你的澄清。你是对的。这确实是一种监督技术。我只是没有意识到我所谓的类别实际上也是类:)
Legend

4

对于高维数据,kd树确实无法很好地工作。由于修剪步骤不再有多大帮助,因为最接近的边缘(一维偏差)几乎总是小于到已知的最近邻居的全尺寸偏差。

但是此外,就我所知,kd树仅适用于Lp范数,并且距离集中效应使基于距离的算法随着维数的增加而降低。

有关更多信息,您可能需要阅读维数的诅咒以及它的各种变体(它不止一个方面!)

我不相信盲目逼近欧几里得最近的邻居有很多用处,例如使用LSH或随机投影。首先可能需要使用更精细的距离功能!


您是否有第一段和第二段的参考?
Chuck

不,但是从通常的“维数诅咒”实例化(参见参考调查)中应该很明显,并尝试找到任何支持除欧几里得以外的任何东西的kd树...支持其他距离是可能的,但并不常见(ELKI允许所有Minkowski距离+平方欧几里得,但大多数将只有欧几里得)。仅考虑kd树仅将维用于修剪,然后将其与涉及所有维的距离进行比较。另外,您的拆分将无法在每个维度上拆分。
埃里希·舒伯特


3

我认为布尔功能的tf-idf上的余弦对于大多数问题都适用。那是因为它在Lucene等许多搜索引擎中使用了久经考验的启发式方法。根据我的经验,欧氏距离对任何类似文本的数据都显示不好的结果。可以使用训练数据和蛮力参数选择来选择不同的权重和k个示例。


3

对于高维数据中的精确knn检索,iDistance可能是最好的方法。您可以将其视为近似Voronoi消息传递。


3

我遇到了同样的问题,可以说以下内容。

  1. 欧几里得距离是一个很好的距离度量标准,但是它在计算上比曼哈顿距离更昂贵,有时结果会稍差一些,因此,我选择后者。

  2. k的值可以凭经验找到。您可以尝试使用其他值,并检查生成的ROC曲线或其他一些精度/召回率指标,以便找到可接受的值。

  3. 欧氏距离和曼哈顿距离都遵循Triangle不等式,因此您可以在公制树中使用它们。确实,当数据的维度超过10个时,KD树的性能会严重下降(我自己也遇到了这个问题)。我发现VP树是更好的选择。


3

如果您在查看所有点数的5%后提早退出,KD树在21个维度上都可以正常工作。 FLANN执行此操作(以及其他加速操作)以匹配128维SIFT向量。(不幸的是,FLANN仅执行欧几里德指标,而快速而可靠的 scipy.spatial.cKDTree 仅执行Lp指标;这些指标可能适合或可能不适合数据。)当然,这里需要进行速度精度折衷。

(如果您可以描述您的Ndata,Nquery,数据分布,这可能会帮助人们尝试类似的数据。)

在我的旧Mac ppc上添加了4月26日的cKDTree的运行时间(带有截止时间),以给出一个非常粗略的可行性想法:

kdstats.py p=2 dim=21 N=1000000 nask=1000 nnear=2 cutoff=1000 eps=0 leafsize=10 clustype=uniformp
14 sec to build KDtree of 1000000 points
kdtree: 1000 queries looked at av 0.1 % of the 1000000 points, 0.31 % of 188315 boxes; better 0.0042 0.014 0.1 %
3.5 sec to query 1000 points
distances to 2 nearest: av 0.131  max 0.253

kdstats.py p=2 dim=21 N=1000000 nask=1000 nnear=2 cutoff=5000 eps=0 leafsize=10 clustype=uniformp
14 sec to build KDtree of 1000000 points
kdtree: 1000 queries looked at av 0.48 % of the 1000000 points, 1.1 % of 188315 boxes; better 0.0071 0.026 0.5 %
15 sec to query 1000 points
distances to 2 nearest: av 0.131  max 0.245


0

欧几里得距离是一个很好的度量标准,可以用来首先找到最近的邻居?如果没有,我有什么选择?

我建议使用软子空间聚类,这是当今非常普遍的方法,其中计算特征权重以找到最相关的尺寸。例如,在使用欧几里德距离时,可以使用这些权重。见维度诅咒常见问题,本文也可以通过以下方式启发您:

用于混合数值和分类数据集的子空间聚类的k均值类型聚类算法

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.