我有数十万个长度为32位的稀疏位串。
我想对他们进行最近邻搜索,查找性能至关重要。我一直在阅读各种算法,但它们似乎是针对文本字符串而不是二进制字符串。我认为局部敏感的散列或光谱散列似乎是很好的候选者,或者我可以研究压缩。这些中的任何一个都能很好地解决我的位串问题吗?任何方向或指导都将不胜感激。
答案 0 :(得分:3)
这是一种快速简便的方法, 然后是以更多内存为代价的更好性能的变体。
In:array Uint X [],例如1M 32位字
通缉:功能near( Uint q )
- > j小hammingdist( q, X[j] )
方法:已排序q
中的二进制搜索X
,
然后线性搜索周围的块。
伪代码:
def near( q, X, Blocksize=100 ):
preprocess: sort X
Uint* p = binsearch( q, X ) # match q in leading bits
linear-search Blocksize words around p
return the hamming-nearest of these.
这很快 - Binary search 1M字 +最近的汉明主义者,面积为100 采取< 10我们在我的Mac ppc。 (这是高度缓存依赖的 - 您的里程将变化。)
这有多接近找到真正最近的X [j]?
我只能试验,不能做数学:
1M随机单词中的1M随机查询,
最近的匹配平均距离为4-5位,
对于真实最接近的距离为3(线性扫描全部为1M):
near32 N 1048576 Nquery 1048576 Blocksize 100
binary search, then nearest +- 50
7 usec
distance distribution: 0 4481 38137 185212 443211 337321 39979 235 0
near32 N 1048576 Nquery 100 Blocksize 1048576
linear scan all 1048576
38701 usec
distance distribution: 0 0 7 58 35 0
使用块大小50和100来运行数据 看看比赛距离是如何下降的。
<小时/> 为了更接近,以两倍的记忆为代价,
Xswap
X
的副本,其中上/下半字交换,
然后返回
near( q, X, Blocksize )
near( swap q, Xswap, Blocksize )
拥有大量内存,可以使用X
的更多位洗牌副本,
例如32次旋转
我不知道Nshuffle和Blocksize的性能如何变化 -
LSH理论家的一个问题。
<小时/> (已添加):近似匹配320位,10个字的位串, 制作10个指针数组,按字0,字1排序...... 并使用上述binsearch搜索块:
nearest( query word 0, Sortedarray0, 100 ) -> min Hammingdist e.g. 42 of 320
nearest( query word 1, Sortedarray1, 100 ) -> min Hammingdist 37
nearest( query word 2, Sortedarray2, 100 ) -> min Hammingdist 50
...
-> e.g. the 37.
这当然会错过近似的比赛,没有一个单词接近, 但它很简单,排序和binsearch快速 。 指针数组占用与数据位完全相同的空间。 100个字,3200位将以完全相同的方式工作 但是:只有当0位和1位的数量大致相等时才有效, 不是99%0位。
答案 1 :(得分:1)
我刚刚发现了一篇解决这个问题的论文。
Randomized algorithms and NLP: using locality sensitive hash function for high speed noun clustering(Ravichandran等,2005)
基本思想类似于丹尼斯的答案(按字母顺序排列不同的位排列),但它包含了一些额外的想法和关于该主题的文章的进一步参考。
它实际上是在我发现它的https://github.com/soundcloud/cosine-lsh-join-spark中实现的。