您的位置:首页 > 理论基础 > 数据结构算法

最近邻算法和向量模型——第二部分——算法和数据结构

2015-12-01 18:13 411 查看
这篇博客是在我上周NYC MachineLearning做得报告基础上改写而成的。内容中包括Annoy,我开源的一个高维空间求(近似)最近邻的工具库。在第一部分,我介绍了几个例子,并说明向量模型是非常有用的。在第二部分,我将解释Annoy是怎么去找近似最近邻的(approximate
nearest neighbor queries),以及相应的算法和数据结构。
 
言归正传,我们的目的是要在一个空间找到一个已知点的最近邻集合。我们看下图是一个二维空间,里面有很多点,当然现实情况,向量模型的维度会比这高很多。



我们的目标是设计一个数据结构,使我们能够以压线性的时间查找一个点的最邻近点集。
我们将构建一棵树,查询时间在 O(log n)。这就是Annoy的原理,实际上,构建的是一个二叉树,其中每个节点都是任意划分的。那我们先看看如何进行一次空间划分:




Annoy通过随机挑选两个点,并使用垂直于这两个点的等距离超平面将集合划分成两部分。图中灰色线是连接两个点,超平面是加粗的黑线。
然后我们按照上述方法在每个子集上进行迭代划分!




一个非常小的二叉树就开始形成了:




我们继续划分:




以此类推,直到每个节点最多剩下K个点。下图是一个K=10的情况:




相应的完整二叉树结构:



 
很好!最后我们得到一颗二叉树,并且这棵树把空间做了划分。这样的好处是原先空间中相邻的点,在树结构上也表现出相互靠近的特点。换句话说,如果两个点在空间上相互靠近,它们也很有可能被多个超平面划分到一起。
 
如果要在空间中查找邻近点,我们只需要遍历这个二叉树。每个中间节点(上图中方形节点)用超平面来定义,所以我们能够计算出该节点的往哪个方向遍历。搜索一个点能够在log时间内完成,这个正好是树的高度。
假如我们要搜索下图中红色X:




二叉树的搜索路径看上去会是这样:




结果我们找到了7个最近邻。非常棒,但仍然有两个问题
1.    如果我们想找到最近邻数目大于7,该怎么办?
2.    有些最近邻在我们遍历的叶子节点的外面
 
技巧1——使用优先队列
这个技巧是,如果一个划分的两边“靠得足够近”(量化方式在后面介绍),我们就两边都遍历。这样就不只是遍历一个节点的一边,我们将遍历更多的点:




与之对应的二叉树遍历路径:




我们可以设置一个阈值,用来表示是否愿意搜索划分“错”的一遍。如果设置为0,我们将总是遍历“对”的一片。但是如果设置成0.5,就按照上面的搜索路径。
这个技巧实际上是利用优先级队列,依据两边的最大距离。好处是我们能够设置比0大的阈值,逐渐增加搜索范围。
 
技巧2——构建一个森林
第二个技巧是构建多棵树即森林。每棵树都是按照任意划分构建。我们将同时搜索所有的树:




我们能够用一个优先级队列,同时搜索所有的树。这样有另外一个好处,搜索会聚焦到那些与已知点靠得最近的那些树——能够把距离最远的空间划分出去。
 
每棵树都包含所有的点,所以当我们搜索多棵树的时候,将找到多棵树上的多个点。如果我们把所有的搜索结果的叶子节点都合在一起,那么得到的最近邻就非常符合要求。




按照这个方法,我们最后找到一个邻近的集合。你可能会注意到,到目前为止,我们都没有提到如何计算点点之间的距离。下一步是计算所有的距离和对点进行排序。




我们根据点距离进行排序,然后返回K个最相近的点。很好!这就是Annoy算法的工作原理。
还是有一个问题,我们实际上仍然丢掉了一些点:




但是正如Annoy中的A,代表了近似(approximate),其实少一些点也是可以接受的。Annoy在实际使用的时候,提供了一种机制可以调整(搜索k),你能够根据它来权衡性能(时间)和准确度(质量)。
 
近似算法的主要思想是通过牺牲一点准确度换取性能的巨大提升(数量级的)。举例来说,我们能够得到一个不错的搜索结果,仅仅是计算1%的点之间的距离——却可以带来100倍相比于穷尽搜索的性能。
树越多效果越好。通过增加树,你更有可能找到你想要的划分。一般来说,只要不超过内存,你可以增加越多越好。
Annoy算法总结:
 
预处理时间:
1.    构建一批二叉树。每棵树都按照随机超平面迭代划分。
Query time:
查询时间
1.    插入每棵树到优先级队列
2.    搜索优先队列中的所有树,直到得到k个候选点
3.    对候选点去重
4.    计算候选点与已知点之间的距离
5.    对候选得到的距离进行排序
6.    返回最近的那几个邻近点
 
如果你感兴趣,请查阅头文件annoylib.h中的_make_tree_get_all_nns
 
OK差不多讲完了,如果你想获取更多信息,请期待我的下一个分享。顺便说一句,请查看这个幻灯片;另外文中的所有图片绘制代码,你也可以看看。
 

(翻译自:http://erikbern.com/2015/10/01/nearest-neighbors-and-vector-models-part-2-how-to-search-in-high-dimensional-spaces/

 

廖博森@DataSpark
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息