我为最近邻搜索编写了一个基本的O(n ^ 2)算法。像往常一样,Matlab 2013a的knnsearch(..)方法工作得更快。
有人能告诉我他们在实施过程中使用了哪种优化方式?
我可以阅读您可能指出的任何文件或文件。
PS:我理解网站上的文档提到了关于kd树的文章作为参考。但据我所知,当列数小于10时,kd树是默认选项。我的是21.如果我错了,请纠正我。
答案 0 :(得分:7)
MathWorks在实现最近邻搜索时所做的最大优化是所有硬件都是在MEX文件中实现的,如编译C而不是MATLAB。
使用像kNN这样的算法(在我有限的理解中)是非常递归的并且难以矢量化,这可能会给出这样的改进,即O()分析只与相当高的n
相关。
更详细地说,knnsearch
命令使用createns
来创建NeighborSearcher
对象。默认情况下,当X
少于10列时,这将是KDTreeSearcher
个对象,当X
超过10列时,它将是ExhaustiveSearcher
个对象(两者都是KDTreeSearcher
和ExhaustiveSearcher
是NeighborSearcher
)的子类。
类NeighbourSearcher
的所有对象都有一个方法knnsearch
(您很少直接调用,而是使用便捷命令knnsearch
而不是此方法)。 knnsearch
KDTreeSearcher
方法直接调用MEX文件进行所有艰苦工作。它位于 matlabroot \ toolbox \ stats \ stats \ @KDTreeSearcher \ private \ knnsearchmex.mexw64。
据我所知,这个MEX文件几乎执行文档页面中引用的Friedman,Bentely和Finkel论文中描述的算法,没有任何结构变化。正如本文的标题所暗示的,该算法是O(log(n))而不是O(n ^ 2)。遗憾的是,MEX文件的内容无法进行检查以确认。
答案 1 :(得分:2)
code构建KD-tree空间分区结构以加快nearest neighbor search,将其想象为构建RDBMS中常用的indexes以加快查找操作。< / p>
除了最近邻搜索之外,此结构还会加速range-searches,从查询点查找距离r
内的所有点。
正如@SamRoberts所指出的,代码的核心在C / C ++中实现为MEX函数。
请注意,knnsearch
选择仅在特定条件下构建KD-tree,否则会回到穷举搜索(通过天真搜索所有点到最近的点)。
请记住,在非常高维数据(和少数实例)的情况下,算法会退化并且不会比穷举搜索更好。一般情况下,当您使用维度d>30
时,搜索KD树的成本将增加到搜索几乎所有点,甚至可能比蛮力搜索更糟糕,因为构建树的开销很大。 / p>
该算法还有其他变体处理高维度,例如ball trees,它在一系列嵌套超球体中对数据进行分区(而不是像沿着笛卡尔轴一样对数据进行分区,如KD树) 。不幸的是,这些并未在官方统计工具箱中实现。如果您有兴趣,请参阅a paper,其中提供了对可用kNN算法的调查。
(以上是搜索kd-tree分区的2d空间,借鉴文档)