【问题标题】:Locate "N Gram" substrings that are smallest distance away from a target string N character long找到距离目标字符串 N 个字符长度最小的“N Gram”子字符串
【发布时间】:2011-05-11 07:53:52
【问题描述】:

我正在寻找一种算法,最好是在 Python 中,它可以帮助我找到最接近目标字符串长度为 N 个字符的现有字符串的子字符串(长度为 N 个字符)。

考虑目标字符串,即 4 个字符长,为:

targetString -> '1111'

假设这是我可用的字符串(我将生成它的子字符串以进行“最佳对齐”匹配):

nonEmptySubStrings -> ['110101']

上述4个字符长的子字符串:

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

我想编写/使用一个“魔术函数”来选择最接近 targetString 的字符串:

someMagicFunction -> ['1101']

更多示例:

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

someMagicFunction -> ['1011']

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

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

这个“魔术函数”是一个众所周知的子字符串问题吗?

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

【问题讨论】:

  • 我很想知道我上面问题的最后一行(粗体)的答案。我的要求似乎在生物信息学中应该相当频繁?哦,这可能与基于汉明距离一样微不足道(在这种情况下,我会修改我的问题以删除 ngram 生成步骤)。我基本上想找到最小值。 nonEmptySubStrings 中的更改次数,以便它将 targetString 作为子字符串。

标签: python string substring string-matching


【解决方案1】:

作为前段时间关于基因匹配的讨论的一部分,我写了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】:

    根据 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 chars 来改变 x chars。

    【讨论】:

    • 你的 'slices' 需要有 'for i in xrange(len(string_) - L + 1):' 而不是 'for i in xrange(len(string_) - L))'汉明距离是 'def diff(str1, str2)' 的一个很好的度量吗?
    • @PoorLuzer,汉明距离似乎是理想的,因为它可以测量不同字符的数量。这就是你想要的吗?你想要实际的子字符串还是它的索引?如果没有,您可能可以在没有功能的情况下完成所有操作。告诉我,我会更新。
    • 我不想知道关于子字符串的任何事情,除了找到最小值。 string_ 中的更改次数,以便它将 target_string 作为子字符串。计算 'min.更改数量需要尽可能快,因为它将处理数千个字符串。字符串是数字和二进制的(即它只有两个不同的数字),以防万一。
    【解决方案3】:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-02-02
      • 2013-12-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-12-10
      • 1970-01-01
      • 2017-02-23
      相关资源
      最近更新 更多