【发布时间】:2013-12-03 19:32:02
【问题描述】:
我正在尝试在 Haskell 中实现一个 kdtree(请参阅 implementation),但我尝试在实现最近邻算法时变得聪明并利用 Haskells 的惰性(请参阅第 46 行)。
虽然它在技术上是正确的,但就是:
minimumBy (compare `on` qd q) vs == head . nearestNeighbours (kdtree 5 vs) $ q
==> True
基于 kdtree 的版本要慢得多(标准:5.38 毫秒 vs 138.44 毫秒,数据点为 500k)。我最初认为这是由于 ordMerge(第 59 行)中的模式匹配过于严格,但我重写了它,根据我的理解,bs 现在应该只根据需要进行评估。
如果是这种情况,算法应该只下降到匹配的桶,并在检查当前最佳最近邻居是否真的是最佳候选时重新下降。
我做了一些分析,nearestNeighhbors 被调用了大约 800 次。给定 8 和 100 个测试用例的树深度,这听起来很合理,不是吗?
刚刚将我的代码上传到github:https://github.com/fhaust/threesg
这应该让你开始:
git clone https://github.com/fhaust/threesg
cd threesg
cabal sandbox init
cabal install --enable-benchmarks --enable-tests
cabal test
cabal bench --benchmark-options="+RTS -K100M -RTS"
(需要-K100M,因为测试集是从 500k 点创建的)
在为 github 创建测试集时,我注意到在正态分布点上,kdtree 搜索的运行速度比线性搜索快很多……可能我的问题不是算法……而是我的测试集:(
【问题讨论】:
-
是的......但这对我没有帮助。它大部分时间都花在
nearestNeighbors.nnl和nearestNeighbors.nnr。 -
你是在比较 kd 树的构造,然后用蛮力找到最近的邻居找到它的最近邻居吗?
-
@DiegoNolan ...在进行基准测试之前不强制kdtree。我希望我写的the
NFDatainstance是正确的。 -
你有我们可以使用的
main函数和示例数据吗?我注意到的主要事情是ordMerge可能没有被内联,as it's recursive:尝试应用蹩脚的静态参数转换技巧,或尝试ordMerge f q p n d = go where go = ...(更好的无点样式),因此递归在常量参数上是封闭的。希望结合dist'的内联将f到p和q的应用程序共享暴露给编译器。让我们知道您发现了什么
标签: haskell lazy-evaluation nearest-neighbor kdtree