在Python中寻找一组字符串的最小汉明距离

7 投票
4 回答
11095 浏览
提问于 2025-04-18 12:27

我有一组大约一百万个字符串(DNA序列),它们存储在一个叫做trans的列表里。我需要找出这个列表中所有序列之间的最小汉明距离。我用了一种简单粗暴的方法来实现这个,但这个程序已经运行了一天多了,还是没有结果。我的代码是

dmin=len(trans[0])
for i in xrange(len(trans)):
    for j in xrange(i+1,len(trans)):
            dist=hamdist(trans[i][:-1], trans[j][:-1])
            if dist < dmin:
                    dmin = dist

有没有更有效的方法来解决这个问题?这里的hamdist是我写的一个函数,用来计算汉明距离。它是

def hamdist(str1, str2):
    diffs = 0
    if len(str1) != len(str2):
        return max(len(str1),len(str2))
    for ch1, ch2 in zip(str1, str2):
        if ch1 != ch2:
          diffs += 1
    return diffs

4 个回答

-1

找出所有字符串之间的汉明距离,并把结果存储在一个数组里。就像这样:

    distance=[]
    for i in trans:
      distance.append(hamdist(i))

然后计算这些距离中的最小值,像这样:

    minimum =min(distance)
3

正如在这个回答中提到的,想要比平方级别的运行时间更快的方法并不多。你需要利用数据的结构。比如说,如果允许的最大汉明距离阈值t相对于字符串的长度n来说很小(例如t=100,n=1000000),你可以这样做:随机选择k列(比如k=1000),只关注这些列中的字符串,然后把它们分到不同的桶里。接下来,你只需要在每个桶内进行字符串的两两比较,假设这两个字符串在未选择的列中才会有不同的地方。对于这个例子,这种假设大约有90%的概率是对的,而且通过重复这个过程,你可以把错误的概率降到非常低。

4

一些建议:

1) sklearn.metrics.hamming_loss 这个工具可能比你自己写的实现要高效得多,即使你需要把字符串转换成数组。

2) 你的字符串都是独一无二的吗?如果是的话,可以去掉重复的部分。

你也可以试试 sklearn.metrics.pairwise.pairwise_distances,比如:

In [1]: from sklearn.metrics.pairwise import pairwise_distances

In [2]: from sklearn.metrics import hamming_loss

In [3]: a = np.array([[3,4,5], [3,4,4],[3,1,1]])

In [4]: import numpy as np

In [5]: a = np.array([[3,4,5], [3,4,4],[3,1,1]])

In [6]: pairwise_distances(metric=hamming_loss)

In [7]: pairwise_distances(a, metric=hamming_loss)
Out[7]: 
array([[ 0.        ,  0.33333333,  0.66666667],
       [ 0.33333333,  0.        ,  0.66666667],
       [ 0.66666667,  0.66666667,  0.        ]])

我没有看到一个只计算上三角的标志,但这应该还是比循环要快。

7

你可以通过添加一个可选参数来优化你的 hamdist 函数,这个参数可以用来存放你目前为止得到的最小距离。这样,如果 diffs 达到这个值,你就可以停止计算距离,因为这个比较会得到一个比最小值更大的距离。

def hamdist(str1, str2,prevMin=None):
    diffs = 0
    if len(str1) != len(str2):
        return max(len(str1),len(str2))
    for ch1, ch2 in zip(str1, str2):
        if ch1 != ch2:
            diffs += 1
            if prevMin is not None and diffs>prevMin:
                return None
    return diffs 

你还需要调整你的主循环,以便能够处理 hamdist 返回的 None 值。

dmin=len(trans[0])
for i in xrange(len(trans)):
    for j in xrange(i+1,len(trans)):
            dist=hamdist(trans[i][:-1], trans[j][:-1])
            if dist is not None and dist < dmin:
                    dmin = dist

撰写回答