搜索字符串,允许在字符串的任何位置上有一个不匹配

25

我正在处理长度为25的DNA序列(如下所示)。我有一个包含230,000个序列的列表,并需要在整个基因组(弓形虫寄生虫)中查找每个序列。我不确定基因组有多大,但远比230,000个序列长得多。

我需要查找每个由25个字符组成的序列,例如(AGCCTCCCATGATTGAACAGATCAT)。

基因组格式化为连续字符串,即(CATGGGAGGCTTGCGGAGCCTGAGGGCGGAGCCTGAGGTGGGAGGCTTGCGGAGTGCGGAGCCTGAGCCTGAGGGCGGAGCCTGAGGTGGGAGGCTT....

我不关心它被发现的位置或次数,只关心是否存在。
我认为这很简单--

str.find(AGCCTCCCATGATTGAACAGATCAT)

但我也想找到一个定义为错误(不匹配)的接近匹配项,可以在任何位置但只有一个位置,并在序列中记录该位置。 我不确定如何做这个。 我唯一能想到的是使用通配符并在每个位置执行带有通配符的搜索。 例如,搜索25次。

例如,

AGCCTCCCATGATTGAACAGATCAT    
AGCCTCCCATGATAGAACAGATCAT

在位置13有一个不匹配的紧密匹配。

速度不是太重要,因为我只需要做3次,但如果它快一些就更好了。

虽然有一些程序可以找到匹配和部分匹配,但我正在寻找一种这些应用程序无法发现的部分匹配类型。

这里有一个类似的帖子是关于Perl的,尽管他们只比较序列而不是搜索连续字符串:

相关帖子

14个回答

29

在继续阅读之前,您是否查看了biopython

似乎您想要找到一个差错为1的近似匹配,且没有插入/删除错误,即汉明距离为1。

如果您有一个汉明距离匹配函数(例如参考Ignacio提供的链接),您可以像这样使用它来搜索第一个匹配项:

any(Hamming_distance(genome[x:x+25], sequence) == 1 for x in xrange(len(genome)))

但是这样会比较慢,因为(1) Hamming距离函数会在第二次替换错误后继续运行 (2) 在失败后,它只会将光标向前移动一个位置,而不是根据所看到的内容跳过一些位置(像Boyer-Moore搜索那样)。

您可以通过使用以下函数来解决(1):

def Hamming_check_0_or_1(genome, posn, sequence):
    errors = 0
    for i in xrange(25):
        if genome[posn+i] != sequence[i]:
            errors += 1
            if errors >= 2:
                return errors
    return errors 

注意:这故意不像Pythonic,而是Cic,因为你需要使用C(也许通过Cython)才能获得合理的速度。
Navarro和Raffinot已经做了一些关于位并行近似Levenshtein搜索的工作(谷歌“Navarro Raffinot nrgrep”),这可以用于Hamming搜索。请注意,位并行方法在查询字符串长度和字母表大小方面存在限制,但您的查询字符串长度为25,字母表大小为4,因此没有问题。更新:跳过对于字母表大小为4的情况可能帮助不大。
当您在谷歌中搜索汉明距离搜索时,您会注意到很多有关在硬件中实现它的内容,而在软件中则很少。这是一个很大的提示,表明您想出的任何算法都应该在C或其他编译语言中实现。
更新:位并行方法的工作代码
我还提供了一种简单的方法来帮助检查正确性,并打包了Paul的re代码的变体进行比较。请注意,使用re.finditer()会提供非重叠的结果,这可能会导致距离1的匹配掩盖精确匹配;请参阅我的最后一个测试案例。
位并行方法具有以下特点:保证线性行为O(N),其中N是文本长度。请注意,朴素方法和正则表达式方法的时间复杂度都是O(NM)(其中M是模式长度)。Boyer-Moore风格的方法最坏情况下的时间复杂度为O(NM),期望时间复杂度为O(N)。此外,当输入必须被缓冲时,可以轻松地使用位并行方法:它可以每次接收一个字节或一个兆字节;没有前瞻,没有缓冲区边界问题。最大的优势是,用C编写的每个输入字节代码的速度非常快。
缺点:模式长度实际上受到快速寄存器中位数的限制,例如32或64。在这种情况下,模式长度为25;没有问题。它使用额外的内存(S_table),其大小与模式中不同字符的数量成比例。在这种情况下,“字母表大小”仅为4;没有问题。 此技术报告提供了详细信息。该算法用于使用Levenshtein距离进行近似搜索。要转换为使用汉明距离,我只需(!)删除处理插入和删除的语句2.1中的部分内容。您会注意到许多参考文献中出现“R”和上标“d”。 “d”是距离。我们只需要0和1。这些“R”变成下面代码中的R0和R1变量。
# coding: ascii

from collections import defaultdict
import re

_DEBUG = 0


# "Fast Text Searching with Errors" by Sun Wu and Udi Manber
# TR 91-11, Dept of Computer Science, University of Arizona, June 1991.
# http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.20.8854

def WM_approx_Ham1_search(pattern, text):
    """Generate (Hamming_dist, start_offset)
    for matches with distance 0 or 1"""
    m = len(pattern)
    S_table = defaultdict(int)
    for i, c in enumerate(pattern):
        S_table[c] |= 1 << i
    R0 = 0
    R1 = 0
    mask = 1 << (m - 1)
    for j, c in enumerate(text):
        S = S_table[c]
        shR0 = (R0 << 1) | 1
        R0 = shR0 & S
        R1 = ((R1 << 1) | 1) & S | shR0
        if _DEBUG:
            print "j= %2d msk=%s S=%s R0=%s R1=%s" \
                % tuple([j] + map(bitstr, [mask, S, R0, R1]))
        if R0 & mask: # exact match
            yield 0, j - m + 1
        elif R1 & mask: # match with one substitution
            yield 1, j - m + 1

if _DEBUG:

    def bitstr(num, mlen=8):
       wstr = ""
       for i in xrange(mlen):
          if num & 1:
             wstr = "1" + wstr
          else:
             wstr = "0" + wstr
          num >>= 1
       return wstr

def Ham_dist(s1, s2):
    """Calculate Hamming distance between 2 sequences."""
    assert len(s1) == len(s2)
    return sum(c1 != c2 for c1, c2 in zip(s1, s2))

def long_check(pattern, text):
    """Naively and understandably generate (Hamming_dist, start_offset)
    for matches with distance 0 or 1"""
    m = len(pattern)
    for i in xrange(len(text) - m + 1):
        d = Ham_dist(pattern, text[i:i+m])
        if d < 2:
            yield d, i

def Paul_McGuire_regex(pattern, text):
    searchSeqREStr = (
        '('
        + pattern
        + ')|('
        + ')|('.join(
            pattern[:i]
            + "[ACTGN]".replace(c,'')
            + pattern[i+1:]
            for i,c in enumerate(pattern)
            )
        + ')'
        )
    searchSeqRE = re.compile(searchSeqREStr)
    for match in searchSeqRE.finditer(text):
        locn = match.start()
        dist = int(bool(match.lastindex - 1))
        yield dist, locn


if __name__ == "__main__":

    genome1 = "TTTACGTAAACTAAACTGTAA"
    #         01234567890123456789012345
    #                   1         2

    tests = [
        (genome1, "ACGT ATGT ACTA ATCG TTTT ATTA TTTA"),
        ("T" * 10, "TTTT"),
        ("ACGTCGTAAAA", "TCGT"), # partial match can shadow an exact match
        ]

    nfailed = 0
    for genome, patterns in tests:
        print "genome:", genome
        for pattern in patterns.split():
            print pattern
            a1 = list(WM_approx_Ham1_search(pattern, genome))
            a2 = list(long_check(pattern, genome))
            a3 = list(Paul_McGuire_regex(pattern, genome))
            print a1
            print a2
            print a3
            print a1 == a2, a2 == a3
            nfailed += (a1 != a2 or a2 != a3)
    print "***", nfailed

1
这至少值得一看,以避免重新发明轮子的事情! - jathanism
1
我在 biopython 上发布了这个问题。他们建议只使用 BLAST 并用 Python 解析结果。由于结果将包括太多/过于广泛的匹配结果。 - Vincent
1
shR0 中的 sh 代表什么? - Randomblue
谢谢。WM_approx_Ham1_search 函数是否能够在文本长度小于100000,模式串长度小于文本长度且字母表基数为27的情况下顺利运行? - Randomblue
@Randomblue: len(text) 不是问题,每次只需要1个字符。len(pattern) 则有很大不同:请参见上文(“缺点:模式长度在快速寄存器中实际上受到限制,例如32位或64位”)。Python 代码应该对短模式可以流畅运行,但对于长模式则速度较慢。 - John Machin

27

Python 正则表达式库支持模糊正则匹配。相比于TRE,它允许在文本中查找正则表达式的所有匹配项(同时支持重叠匹配)。

import regex
m=regex.findall("AA", "CAG")
>>> []
m=regex.findall("(AA){e<=1}", "CAAG") # means allow up to 1 error
m
>>> ['CA', 'AG']

6
为什么这个结果不会同时返回'AA' - warship
要查找所有实例,包括重叠的实例:pm=regex.findall("(AA){e<=1}", "CAAG", overlapped=True) - Dmitri
10
注意,{e<=1} 允许进行 1 次替换、插入或删除操作;如果只允许进行 1 次替换操作,请使用 {s<=1} - tflutre
2
这个方法的一个快速注释 - 它似乎不起作用:例如,在“{e<=1}”时,无法在“'CACCGCCCATTTCCAGCACGGAAGATAGGTTCTGGTGTGTCACCGTCCATTTCCCGAACCGGTCTCCCTCACCAGCTCGACCCACACTAGCTGTCCATCCTGAGGCGC'”中找到“TCACCGCCCATTTCC”,但它应该能够找到。 - suze1992
@suze1992 你向“regex”的作者报告了错误吗? - bli
显示剩余4条评论

7

我在谷歌上搜索“弓形虫基因组”,以在线查找一些基因组文件。我找到了一个看起来很接近的文件,标题为“TgondiiGenomic_ToxoDB-6.0.fasta”,大小约为158MB,位于http://toxodb.org。我使用以下pyparsing表达式提取基因序列,仅用了不到2分钟:

fname = "TgondiiGenomic_ToxoDB-6.0.fasta"
fastasrc = open(fname).read()   # yes! just read the whole dang 158Mb!

"""
Sample header:
>gb|scf_1104442823584 | organism=Toxoplasma_gondii_VEG | version=2008-07-23 | length=1448
"""
integer = Word(nums).setParseAction(lambda t:int(t[0]))
genebit = Group(">gb|" + Word(printables)("id") + SkipTo("length=") + 
                "length=" + integer("genelen") + LineEnd() + 
                Combine(OneOrMore(Word("ACGTN")),adjacent=False)("gene"))

# read gene data from .fasta file - takes just under a couple of minutes
genedata = OneOrMore(genebit).parseString(fastasrc)

(惊喜!一些基因序列包含了一串“N”!这是怎么回事?!)

然后我编写了这个类作为 pyparsing Token 类的子类,用于进行相似匹配:

class CloseMatch(Token):
    def __init__(self, seq, maxMismatches=1):
        super(CloseMatch,self).__init__()
        self.name = seq
        self.sequence = seq
        self.maxMismatches = maxMismatches
        self.errmsg = "Expected " + self.sequence
        self.mayIndexError = False
        self.mayReturnEmpty = False

    def parseImpl( self, instring, loc, doActions=True ):
        start = loc
        instrlen = len(instring)
        maxloc = start + len(self.sequence)

        if maxloc <= instrlen:
            seq = self.sequence
            seqloc = 0
            mismatches = []
            throwException = False
            done = False
            while loc < maxloc and not done:
                if instring[loc] != seq[seqloc]:
                    mismatches.append(seqloc)
                    if len(mismatches) > self.maxMismatches:
                        throwException = True
                        done = True
                loc += 1
                seqloc += 1
        else:
            throwException = True

        if throwException:
            exc = self.myException
            exc.loc = loc
            exc.pstr = instring
            raise exc

        return loc, (instring[start:loc],mismatches)

对于每一次匹配,这个函数会返回一个元组,其中包含实际匹配的字符串和不匹配位置的列表。对于完全匹配,第二个值自然会返回一个空列表。(我喜欢这个类,我觉得我会在下一个pyparsing版本中添加它。)

接下来,我运行了这段代码,在从.fasta文件读取的所有序列中搜索“最多2个不匹配”的匹配项(记住genedata是一个ParseResults组成的序列,每个组都包含一个id、一个整数长度和一个序列字符串):

searchseq = CloseMatch("ATCATCGAATGGAATCTAATGGAAT", 2)
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
        print
    print

我从基因片段中随机选择了搜索序列,以确保我能找到完全匹配,并出于好奇心想看看有多少个1和2元素不匹配。

这需要一点时间才能运行。45分钟后,我得到了以下输出,列出了每个ID和基因长度,以及找到的任何部分匹配:

scf_1104442825154 (964)
------------------------

scf_1104442822828 (942)
------------------------

scf_1104442824510 (987)
------------------------

scf_1104442823180 (1065)
------------------------
...

我开始感到泄气,直到出现以下匹配项:

scf_1104442823952 (1188)
------------------------
MATCH: ATCATCGAATGGAATCTAATGGAAT
FOUND: ATCATCGAACGGAATCGAATGGAAT
                *      *        
at location 33

MATCH: ATCATCGAATGGAATCTAATGGAAT
FOUND: ATCATCGAATGGAATCGAATGGAAT
                       *        
at location 175

MATCH: ATCATCGAATGGAATCTAATGGAAT
FOUND: ATCATCGAATGGAATCGAATGGAAT
                       *        
at location 474

MATCH: ATCATCGAATGGAATCTAATGGAAT
FOUND: ATCATCGAATGGAATCGAATGGAAT
                       *        
at location 617

MATCH: ATCATCGAATGGAATCTAATGGAAT
FOUND: ATCATCGAATGGAATCGAATAGAAT
                       *   *    
at location 718

MATCH: ATCATCGAATGGAATCTAATGGAAT
FOUND: ATCATCGAATGGATTCGAATGGAAT
                    *  *        
at location 896

MATCH: ATCATCGAATGGAATCTAATGGAAT
FOUND: ATCATCGAATGGAATCGAATGGTAT
                       *     *  
at location 945

最后,我的准确匹配结果为:

scf_1104442823584 (1448)
------------------------
MATCH: ATCATCGAATGGAATCTAATGGAAT
FOUND: ATCATCGAATGGACTCGAATGGAAT
                    *  *        
at location 177

MATCH: ATCATCGAATGGAATCTAATGGAAT
FOUND: ATCATCGAATGGAATCAAATGGAAT
                       *        
at location 203

MATCH: ATCATCGAATGGAATCTAATGGAAT
FOUND: ATCATCAAATGGAATCGAATGGAAT
             *         *        
at location 350

MATCH: ATCATCGAATGGAATCTAATGGAAT
FOUND: ATCATCGAATGGAATCGAATGGAAA
                       *       *
at location 523

MATCH: ATCATCGAATGGAATCTAATGGAAT
FOUND: ATCATCAAATGGAATCGAATGGAAT
             *         *        
at location 822

MATCH: ATCATCGAATGGAATCTAATGGAAT
FOUND: ATCATCGAATGGAATCTAATGGAAT
<exact match>
at location 848

MATCH: ATCATCGAATGGAATCTAATGGAAT
FOUND: ATCGTCGAATGGAGTCTAATGGAAT
          *         *           
at location 969

所以虽然这并没有创造任何速度记录,但我完成了工作,并找到了一些2匹配项,如果感兴趣的话。

为了比较,这里是一个基于正则表达式的版本,只能找到1个不匹配的匹配项:

import re
seqStr = "ATCATCGAATGGAATCTAATGGAAT"
searchSeqREStr = seqStr + '|' + \
    '|'.join(seqStr[:i]+"[ACTGN]".replace(c,'') +seqStr[i+1:] 
             for i,c in enumerate(seqStr))

searchSeqRE = re.compile(searchSeqREStr)

for g in genedata:
    print "%s (%d)" % (g.id, g.genelen)
    print "-"*24
    for match in searchSeqRE.finditer(g.gene):
        print "MATCH:", seqStr
        print "FOUND:", match.group(0)
        print "at location", match.start()
        print
    print

起初,我试图搜索原始的FASTA文件源本身,但对比pyparsing版本,发现匹配结果很少。后来我意识到一些匹配结果必须跨越换行符,因为fasta文件输出在n个字符处换行。

所以,在第一个pyparsing步骤中提取基因序列进行匹配后,这个基于RE的搜索器花了大约1-1/2分钟的时间扫描所有未经文本包装的序列,找到了与pyparsing解决方案相同的所有1个不匹配的条目。


N的序列根据维基百科上的FASTA格式页面是AGCT序列。 - Justin Peel
哇!你获得了奖品。我也喜欢 Hamming,但如果我要做更多类似的事情,我会从你的代码开始。看看我对自己问题的回答。nexalign 的速度真是惊人,30秒内就能在我的文件中找到每个1个不匹配的地方,并与 me49 gondii fasta 文件进行比对。 - Vincent
不要忘记,原始的fasta文件将序列列在每行60个字符中,但实际基因序列是许多这样的行的连接。所需匹配可能跨越换行符。 - PaulMcG
CloseMatch在2016年9月加入了pyparsing 2.1.9。最新的Py2兼容版本是2.4.7,最新版本是3.0.9(3.0.10将于七月发布)。 - PaulMcG
这是链接:https://pyparsing-docs.readthedocs.io/en/latest/pyparsing.html?highlight=close#pyparsing.CloseMatch - undefined

3
>>> import re
>>> seq="AGCCTCCCATGATTGAACAGATCAT"
>>> genome = "CATGGGAGGCTTGCGGAGCCTGAGGGCGGAGCCTGAGGTGGGAGGCTTGCGGAGTGCGGAGCCTGAGCCTGAGGGCGGAGCCTGAGGTGGGAGGCTT..."
>>> seq_re=re.compile('|'.join(seq[:i]+'.'+seq[i+1:] for i in range(len(seq))))

>>> seq_re.findall(genome)  # list of matches
[]  

>>> seq_re.search(genome) # None if not found, otherwise a match object

这个函数会在第一个匹配项时停止搜索,因此在存在多个匹配项时可能会更快。
>>> print "found" if any(seq_re.finditer(genome)) else "not found"
not found

>>> print "found" if seq_re.search(genome) else "not found" 
not found

>>> seq="CAT"
>>> seq_re=re.compile('|'.join(seq[:i]+'.'+seq[i+1:] for i in range(len(seq))))
>>> print "found" if seq_re.search(genome) else "not found"
found

对于长度为10,000,000的基因组,单个线程扫描230,000个序列需要大约2.5天的时间,因此您可能需要将任务分割到几个核心/ CPU上。

在此运行此算法时,您始终可以开始实施更有效的算法 :)

如果您希望搜索单个删除或添加元素,请将正则表达式更改为:

>>> seq_re=re.compile('|'.join(seq[:i]+'.{0,2}'+seq[i+1:] for i in range(len(seq))))

基因组大小为80兆碱基。所以我有很多时间来获得更好的算法。有没有一种好的/简单的方法可以在Python内部将其分割? - Vincent
@Vincent,可能值得将此作为单独的问题来询问。无论使用哪种算法,将任务分解成子任务是值得的。您有多少个可用的核心/ CPU? - John La Rooy
@Vincent,请查看此问题:https://dev59.com/qeo6XIcBkEYKwwoYTzAw - John La Rooy
我看到了一个使用fnmatch.fnmatch()的解决方案,你知道那种方法可能有什么不同吗? - Vincent

3

4
他问题的最接近答案是计算两个字符串之间的汉明距离的函数。他需要一个近似的“搜索”函数,而不是一个近似的“匹配”函数。 - John Machin

1

我也遇到了这个问题,但是建议使用的regex包在正则表达式中使用“e”时不能按预期工作,特别是对于查询和搜索序列中的插入/删除。例如,这个无法找到匹配项:regex.search("xxgyy" + "{e<=1}", "xxggyy")

最终我找到了一个可行的包!它是fuzzysearch包中的find_near_matches()函数!https://github.com/taleinat/fuzzysearch

它利用了Levenshtein距离(max_l_dist)。

>>> from fuzzysearch import find_near_matches
# search for 'PATTERN' with a maximum Levenshtein Distance of 1
>>> find_near_matches('PATTERN', '---PATERN---', max_l_dist=1)
[Match(start=3, end=9, dist=1, matched="PATERN")]

如果你想获取返回值:

>>> x= find_near_matches('PATTERN', '---PATERN---', max_l_dist=1)
## get the start position
>>> x[0].start
3
## get the matched string
>>> x[0].matched
'PATERN'

1
你可以用所有希望匹配的不同序列创建一个trie。现在棘手的部分是制作向下遍历trie的深度优先搜索函数,该函数允许最多一次失配。
这种方法的好处是可以一次搜索所有序列。这将为您节省大量比较操作。例如,当您从顶部节点开始并沿着“A”分支向下移动时,您刚刚保存了许多千次比较,因为您刚刚与所有以“A”开头的序列立即匹配了。考虑一个与给定序列完全匹配的基因组片段。如果您在序列列表中有另一个序列,在最后一个符号上仅有不同,那么使用trie刚刚节省了23次比较操作。

这里有一种实现方法。将 'A','C','T','G' 转换为 0、1、2、3 或其变体。然后使用元组的元组作为您的 trie 结构。在每个节点上,数组中的第一个元素对应于 'A',第二个元素对应于 'C',依此类推。如果 'A' 是该节点的分支,则该节点的元组的第一项是另一个由 4 个元素组成的元组。如果没有 'A' 分支,则将第一项设置为 0。在 trie 的底部是具有该序列 ID 的节点,以便将其放入匹配列表中。

以下是递归搜索函数,允许在这种 trie 中出现一个不匹配:

def searchnomismatch(node,genome,i):
    if i == 25:
        addtomatches(node)
    else:
        for x in range(4):
            if node[x]:
                if x == genome[i]:
                    searchnomismatch(node[x],genome,i+1)
                else:
                    searchmismatch(node[x],genome,i+1,i)

def searchmismatch(node,genome,i,where):
    if i == 25:
        addtomatches(node,where)
    else:
        if node[genome[i]]:
            searchmismatch(node[genome[i]],genome,i+1,where)

在这里,我会以类似以下的方式开始搜索

searchnomismatch(trie,genome[ind:ind+25],0)

addtomatches是类似于的东西

def addtomatches(id,where=-1):
    matches.append(id,where)

其中等于-1表示没有不匹配的情况。无论如何,我希望我表达得足够清楚,让你明白了。


有趣的是,我首先想到的是将基因组的所有长度为25的子串制作成trie,并以同样的方式将每个候选项与之匹配。这需要更多的内存。我认为您的方法仍可以进一步优化,以实现Aho-Corasick字符串匹配的一般化。 - Darius Bacon
@Darius 是的,我仍然认为trie是解决这个问题的一个非常好的方法。我不认为内存会太多,特别是如果使用更节省内存的radix trie。我计算出,在最坏的情况下(使用基本trie),需要访问925个节点才能找到与基因组片段匹配的所有序列。平均情况远低于此。这对我来说似乎相当快。我将研究Aho-Corasick算法。 - Justin Peel
当然 - 我的答案变体需要更多的内存。我已经点赞了这个回答,这是一些愚蠢的StackOverflow错误,将我的投票转移到了其他随机的答案 - 这种情况以前发生过。希望这次能成功。 - Darius Bacon
顺便说一下,Aho-Corasick的思想是逐字节地检查基因组,而无需备份,而不是一次检查25个字节帧。通过像匹配基因组一样遍历尝试来提前编译状态机,但是还没有实际查看基因组--只记录测试和状态。 - Darius Bacon
(这相当于gnibbler的答案,但Python内置的正则表达式实现显然不会创建状态机,而是回溯,所以在这个问题上失利。) - Darius Bacon

1

这暗示了最长公共子序列问题。字符串相似性的问题在于需要对连续的230000个序列进行测试;因此,如果您将您的25个序列之一与连续的字符串进行比较,则会得到非常低的相似度。

如果您计算您的25个序列与连续字符串之间的最长公共子序列,则当长度相同时,您将知道它是否在字符串中。


1

我尝试了一些解决方案,但正如已经写过的那样,当处理大量序列(字符串)时它们速度很慢。

我想到使用bowtie并映射感兴趣的子字符串(soi)与包含FASTA格式字符串的参考文件。您可以提供允许的不匹配数(0..3),并在允许的不匹配情况下返回字符串以使soi映射到它们。这个方法效果很好,而且非常快速。


0

我认为下面的代码简单而方便。

in_pattern = "";
in_genome = "";
in_mistake = d;
out_result = ""


kmer = len(in_pattern)

def FindMistake(v):
    mistake = 0
    for i in range(0, kmer, 1):
        if (v[i]!=in_pattern[i]):
            mistake+=1
        if mistake>in_mistake:
            return False
    return True


for i in xrange(len(in_genome)-kmer+1):
    v = in_genome[i:i+kmer]
    if FindMistake(v):
        out_result+= str(i) + " "

print out_result

您可以轻松地插入您想要检查的基因组和片段,并设置不匹配值。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接