找到与目标字符串N字符长度最小距离的“N Gram”子字符串

时间:2010-11-17 09:40:27

标签: python string substring string-matching

我正在寻找一种算法,最好用Python来帮助我找到最接近目标字符串N字符长的现有字符串(N字符长)的子字符串。

将目标字符串(即4个字符长)视为:

targetString -> '1111'

假设这是我可以使用的字符串(我将为“最佳对齐”匹配生成此字符串):

nonEmptySubStrings -> ['110101']

以上4个字符的子串:

nGramsSubStrings -> ['0101', '1010', '1101']

我想编写/使用“Magic Function”来选择最接近targetString的字符串:

someMagicFunction -> ['1101']

更多例子:

nonEmptySubStrings -> ['101011']
nGramsSubStrings -> ['0101', '1010', '1011']

someMagicFunction -> ['1011']

nonEmptySubStrings -> ['10101']
nGramsSubStrings -> ['0101', '1010']

someMagicFunction -> ['0101', '1010']

这个“魔术功能”是一个众所周知的子串问题吗?

我真的很想找到分钟。 nonEmptySubStrings中的更改次数,以便将targetString作为子字符串。

3 个答案:

答案 0 :(得分:3)

我相信你需要Edit DistancePeter Norvig's spelling corrector是python中的一个实现示例。这是一个implementation of Levenshtein Distance。 另请参阅this question

编辑: 这在生物信息学中相当频繁。参见例如FASTABLAST。生物信息学有许多种类的算法。有关方法的调查,请参阅Sequence Alignment

答案 1 :(得分:2)

作为前一段时间关于基因匹配的讨论的一部分,我写了this pyparsing example,实现了一个pyparsing类CloseMatch。通常,pyparsing表达式返回包含匹配字符串和任何命名结果的结构,但CloseMatch返回包含匹配字符串的2元组和匹配字符串中的不匹配位置列表。以下是CloseMatch的使用方法:

searchseq = CloseMatch("TTAAATCTAGAAGAT", 3)
for g in genedata: 
    print "%s (%d)" % (g.id, g.genelen) 
    print "-"*24 
    for t,startLoc,endLoc in searchseq.scanString(g.gene): 
        matched, mismatches = t[0] 
        print "MATCH:", searchseq.sequence 
        print "FOUND:", matched 
        if mismatches: 
            print "      ", ''.join(' ' if i not in mismatches else '*'  
                            for i,c in enumerate(searchseq.sequence)) 
        else: 
            print "<exact match>" 
        print "at location", startLoc 

以下是部分匹配的示例输出:

organism=Toxoplasma_gondii_RH (258)
------------------------
MATCH: TTAAATCTAGAAGAT
FOUND: TTAAATTTAGGAGCT
             *   *  * 
at location 195

请注意,此类未找到重叠匹配项。这仍然可以完成,但是使用scanString的方法略有不同(我将在下一个pyparsing版本中包含这个方法)。

答案 2 :(得分:1)

根据OP的评论提问,这是所希望的

import functools

def edit_distance(str1, str2): 
    #implement it here

f = functools.operator(edit_distance, target_string)
return min(f(s) for s in slices(string_))   # use slices from below

这将返回任何子字符串到目标字符串的最小编辑距离。它不会指示哪个字符串或其索引是什么。它可以很容易地修改 所以尽管如此。


天真的方式,这可能是最好的方式,是

import functools

def diff(str1, str2):
    # However you test the distance gets defined here. e.g. Hamming distance, 
    # Levenshtein distance, etc.


def slices(string_, L):
    for i in xrange(len(string_) - L + 1)):
        yield string_[i:i+L]

best_match = min(slices(string_), key=functools.partial(diff, target_string))

这不会返回发生子字符串的索引。当然你没有在你的问题中指明你需要它;)

如果你想要比这更好,它将取决于你如何测量距离,并且基本上归结为避免检查一些子串通过推断你必须改变至少x个字符以获得更好的匹配比你已经拥有的。那时,您可以通过跳过x字符来改变x字符。