【发布时间】:2013-01-21 01:33:37
【问题描述】:
我有一个包含约 100 万个唯一 16 个字符的字符串的列表(一个称为 VEC 的数组),我想计算 Python 中每个字符串的最小成对汉明距离(一个称为 RES 的数组)。基本上,我一次计算一行完整的成对距离矩阵,但只将每行的最小值存储在 RES 中。
VEC= ['AAAAAAAAAAAAAAAA','AAAAAAAAAAAAAAAT','AAAAGAAAAAATAAAA'...]
所以 dist(VEC[1],VEC[2])=1, dist(VEC[1],VEC[3])=2 等等...并且 RES[1]=1。使用这些页面中的提示和技巧,我想出了:
#METHOD#1:
import Levenshtein
import numpy
RES=99*numpy.ones(len(VEC))
i=0
for a in VEC:
dist=numpy.array([Levenshtein.hamming(a,b) for b in VEC] ) #array of distances
RES[i]=numpy.amin(dist[dist>0]) #pick min distance greater than zero
i+=1
仅 10,000 的缩短 VEC 大约需要 70 秒,但如果我将其推断为整百万,则需要 8 天。我的方法似乎很浪费,因为我正在重新计算距离矩阵的对称部分,所以我尝试计算矩阵的一半,同时更新每一行的 RES:
#METHOD #2:
import Levenshtein
import numpy
RES=99*numpy.ones(len(VEC))
for i in range(len(VEC)-1):
dist=[Levenshtein.hamming(VEC[i],VEC[j]) for j in range(i+1, len(VEC))]
RES[i]=min(numpy.amin(dist),RES[i])
#update RES as you go along:
k=0
for j in range(i+1,len(VEC)):
if dist[k]<RES[j]:
RES[j]=dist[k]
k+=1
可能不足为奇,第二种方法几乎需要两倍的时间(117 秒),所以它不是很好。无论如何,任何人都可以推荐改进/更改以使其更快吗?
【问题讨论】:
-
这可能需要很长时间。您可以尝试减少搜索空间,也许通过计算每个字符串中的字符集,如果它们不相交则不计算距离。你对字符串的结构有什么额外的了解吗?如果这样做,可能会进一步限制搜索。
-
计算给定行中的第一个成对距离。现在对于同一行中的所有其他距离计算,在距离超过此初始距离后停止它。如果它更短,请更新您当前的最小值并重复。这不会降低时间复杂度,但可能会根据您的字符串的排序方式有很大帮助。此外,这个问题很简单,可以用 C 重新编码并获得另一个不断减少的内容。
-
另外,您是否使用过
scipy.distance?它有一个汉明距离度量。我不知道 Levenshtein 库的优化程度如何,但是通过将数据转换为大型 numpy 数组并使用 scipy 工具,您可能会看到收益。 -
每个字符串都应该是随机的,但我正在研究一些聚类方法。我希望我至少能够得到这个距离矩阵的简化版本作为比较点。检查其他距离计算是一个好主意。 Levenshtein.hamming() 绝对比我的“for”循环实现更快。在找到第一个最小值后停止计算每一行的想法可能会有所帮助。我按字母顺序对字符串进行排序,因此有时相似的字符串会彼此相邻。谢谢。
-
@jfb 我并不是要在第一个局部最小值处停止,而是我的意思是说你在超过当前最小距离后停止计算一对之间的距离。如果您可以修改数据,以便使用 VP-tree 等数据结构,那么一切都可能变得更快。