Поиск строки с учетом одного несоответствия в любом месте строки

Я работаю с последовательностями ДНК длиной 25 (см. Примеры ниже). У меня есть список из 230 000, и мне нужно искать каждую последовательность во всем геноме (паразит toxoplasma gondii). Я не уверен, насколько велик геном, но он намного длиннее 230 000 последовательностей.

Мне нужно найти каждую из моих последовательностей из 25 символов, например (AGCCTCCCATGATTGAACAGATCAT).

Геном отформатирован как непрерывная строка, т.е. (CATGGGAGGCTTGCGGAGCCTGAGGGCGGAGCCTGAGGTGGGAGGCTTGCGGAGTGCGGAGCCTGAGCCTGAGGGCGGAGCCTGAGGTGGGAGGCTT....)

Меня не волнует, где и сколько раз он был найден, только то, есть он или нет.
Думаю, это просто -

str.find(AGCCTCCCATGATTGAACAGATCAT)

Но я также хочу найти близкое совпадение, определенное как неправильное (несоответствующее) в любом месте, но только в одном месте, и записать это место в последовательности. Я не знаю, как это сделать. Единственное, что я могу придумать, - это использовать подстановочный знак и выполнять поиск с подстановочным знаком в каждой позиции. То есть поиск 25 раз.

Например,

AGCCTCCCATGATTGAACAGATCAT    
AGCCTCCCATGATAGAACAGATCAT

Близкое совпадение с несовпадением в позиции 13.

Скорость - не большая проблема, потому что я делаю это всего 3 раза, хотя было бы неплохо, если бы это было быстро.

Существуют программы, которые делают это - находят совпадения и частичные совпадения, - но я ищу частичное совпадение, которое невозможно обнаружить с помощью этих приложений.

Вот похожий пост для perl, хотя они только сравнивают последовательности, а не ищут непрерывную строку:

Связанное сообщение


person Vincent    schedule 10.03.2010    source источник


Ответы (12)


Прежде чем продолжить, смотрели ли вы на биопайтон?

Похоже, что вы хотите найти приблизительные совпадения с одной ошибкой замены и нулевыми ошибками вставки / удаления, то есть с расстоянием Хэмминга, равным 1.

Если у вас есть функция сопоставления расстояния Хэмминга (см., Например, ссылку, предоставленную Игнасио), вы можете использовать ее следующим образом для поиска первого совпадения:

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

но это было бы довольно медленно, потому что (1) функция расстояния Хэмминга будет продолжать измельчать после второй ошибки подстановки (2) после неудачи, она перемещает курсор на единицу, а не пропускает вперед, основываясь на том, что она увидела (как функция Бойера- Поиск Мура).

Вы можете преодолеть (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), чтобы получить разумную скорость.

Некоторая работа над побитно-параллельным приближенным поиском Левенштейна с пропуском была проделана Наварро и Раффино (Google "Navarro Raffinot nrgrep"), и это может быть адаптировано для поиска Хэмминга. Обратите внимание, что у бит-параллельных методов есть ограничения по длине строки запроса и размеру алфавита, но у вас 25 и 4 соответственно, так что проблем нет. Обновление: пропуск, вероятно, не очень помогает с размером алфавита 4.

Когда вы загуглите поиск по расстоянию Хэмминга, вы заметите много вещей о его аппаратной реализации, а не о программном обеспечении. Это большой намек на то, что, возможно, любой алгоритм, который вы придумаете, должен быть реализован на C или другом скомпилированном языке.

Обновление: Рабочий код для параллельного метода

Я также предоставил упрощенный метод, помогающий с проверкой правильности, и я упаковал вариант кода Paul re для некоторых сравнений. Обратите внимание, что использование re.finditer () дает неперекрывающиеся результаты, и это может привести к тому, что совпадение с расстоянием 1 затеняет точное совпадение; см. мой последний тестовый пример.

Бит-параллельный метод имеет следующие особенности: гарантированное линейное поведение O (N), где N - длина текста. Обратите внимание, что наивный метод - O (NM), как и метод регулярных выражений (M - длина шаблона). Метод Бойера-Мура будет наихудшим случаем O (NM) и ожидаемым O (N). Также бит-параллельный метод можно легко использовать, когда ввод должен быть буферизован: он может подаваться по байту или мегабайту за раз; нет предвидения, нет проблем с границами буфера. Большое преимущество: скорость этого простого байтового кода ввода при кодировании на C.

Недостатки: длина шаблона фактически ограничена количеством бит в быстром регистре, например. 32 или 64. В этом случае длина шаблона равна 25; нет проблем. Он использует дополнительную память (S_table), пропорциональную количеству различных символов в шаблоне. В данном случае «размер алфавита» всего 4; нет проблем.

Подробности см. В этом техническом отчете. Приведен алгоритм приближенного поиска по расстоянию Левенштейна. Чтобы преобразовать в использование расстояния Хэмминга, я просто (!) Удалил части инструкции 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
person John Machin    schedule 10.03.2010
comment
На это стоит взглянуть как минимум, чтобы избежать повторного изобретения колеса! - person jathanism; 11.03.2010
comment
Я задаю этот вопрос по биопайтону. Они предложили просто использовать BLAST и анализировать результаты с помощью python. Поскольку результаты будут включать в себя многие / общие результаты матча. - person Vincent; 11.03.2010
comment
Что означает sh в shR0? - person Randomblue; 21.02.2012
comment
Спасибо. Должен ли WM_approx_Ham1_search работать гладко для len(text) < 100000, len(pattern) < len(text) и алфавита с мощностью 27? - person Randomblue; 21.02.2012
comment
@Randomblue: len (текст) не проблема, для этого нужно только 1 символ за раз. len (шаблон) совершенно другой: см. выше (Недостатки: длина шаблона фактически ограничена количеством бит в быстром регистре, например, 32 или 64). Код Python должен работать плавно, но МЕДЛЕННО для длинных шаблонов. - person John Machin; 21.02.2012

Библиотека Python regex поддерживает нечеткое сопоставление регулярных выражений. Одним из преимуществ перед TRE является то, что он позволяет находить все совпадения регулярного выражения в тексте (также поддерживает перекрывающиеся совпадения ).

import regex
m=regex.findall("AA", "CAG")
>>> []
m=regex.findall("(AA){e<=1}", "CAAG") # means allow up to 1 error
m
>>> ['CA', 'AG']
person sefakilic    schedule 11.06.2012
comment
Почему это тоже не возвращает 'AA'? - person warship; 12.07.2015
comment
Чтобы найти все экземпляры, включая перекрывающиеся: pm=regex.findall("(AA){e<=1}", "CAAG", overlapped=True) - person Dmitri; 10.11.2015
comment
внимание, {e<=1} разрешает 1 замену, вставку или удаление; используйте {s<=1}, если вы хотите разрешить только 1 замену - person tflutre; 10.06.2016
comment
быстрое замечание по этому методу - похоже, он не работает: например. не найдет TCACCGCCCATTTCC в 'CACCGCCCATTTCCAGCACGGAAGATAGGTTCTGGTGTGTCACCGTCCATTTCCCGAACCGGTCTCCCTCACCAGCTCGACCCACACTAGCTGTCCATCCTGAGGCGC', когда он должен найти {e ‹= 1}. - person suze1992; 05.09.2017
comment
@ suze1992 Вы сообщали авторам regex об ошибке? - person bli; 05.02.2018
comment
Примечание. Возможно, вам придется избегать фигурных скобок: {{e ‹= 1}} - person adam.r; 23.03.2018
comment
Просто примечание, но комментарий suze1992 больше не соответствует действительности. Я протестировал его, и он работал нормально. - person jeffpkamp; 22.01.2020

Я погуглил по запросу "геном паразита toxoplasma gondii", чтобы найти некоторые из этих файлов генома в Интернете. Я нашел то, что мне показалось очень близким, файл под названием "TgondiiGenomic_ToxoDB-6.0.fasta" на http://toxodb.org, размером около 158Мб. Я использовал следующее выражение 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 для выполнения близких совпадений:

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.)

Затем я запустил этот код для поиска совпадений «до 2-несовпадений» во всех последовательностях, считанных из файла .fasta (напомним, что genedata - это последовательность групп ParseResults, каждая из которых содержит идентификатор, целую длину и строка последовательности):

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 минут у меня был этот вывод, в котором перечислены каждый идентификатор и длина гена, а также все найденные частичные совпадения:

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

Так что, хотя это не установило никаких рекордов скорости, я выполнил свою работу и нашел еще несколько совпадений на случай, если они могут быть интересны.

Для сравнения, вот версия на основе RE, которая находит только одно несоответствие:

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 минуты, чтобы просканировать все последовательности без обтекания текстом, чтобы найти все те же записи с 1-несоответствием. что решение pyparsing сделало.

person PaulMcG    schedule 11.03.2010
comment
Буквы N представляют собой последовательности AGCT в соответствии со страницей википедии о формате FASTA. - person Justin Peel; 11.03.2010
comment
Вау! Вы получаете приз. Мне тоже нравится Хэмминга, но если я когда-нибудь собираюсь делать что-то подобное, я бы начал с вашего кода. Взгляните на мой ответ на мой собственный вопрос. Просто поразительно, насколько быстр nexalign. Обнаружено каждое 1 несоответствие моего файла с файлом fasta me49 gondii за 30 секунд. - person Vincent; 12.03.2010
comment
Не забывайте, что в исходном файле fasta последовательности перечислены в 60-символьных строках, но фактическая последовательность гена представляет собой конкатенацию многих таких строк. Желаемое совпадение может располагаться на новой строке. - person PaulMcG; 12.03.2010

Вы можете найти различные процедуры в Python-Levenshtein, которые могут пригодиться.

person Ignacio Vazquez-Abrams    schedule 10.03.2010
comment
Наиболее близким ответом на его вопрос является функция, которая вычисляет расстояние Хэмминга между двумя струнами. Ему нужна функция приблизительного поиска, а не функция приблизительного совпадения. - person John Machin; 11.03.2010

>>> 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 у вас будет примерно 2,5 дня для одного потока для сканирования 230 000 последовательностей, поэтому вы можете разделить задачу на несколько ядер / ЦП.

Вы всегда можете приступить к реализации более эффективного алгоритма, пока он работает :)

Если вы хотите найти отдельные отброшенные или добавленные элементы, измените регулярное выражение на это

>>> seq_re=re.compile('|'.join(seq[:i]+'.{0,2}'+seq[i+1:] for i in range(len(seq))))
person John La Rooy    schedule 10.03.2010
comment
геном составляет 80мега оснований. Так что у меня будет много времени, чтобы разработать алгоритм получше. Есть ли хороший / простой способ разделить это изнутри Python? - person Vincent; 11.03.2010
comment
@Vincent, наверное стоит задать это как отдельный вопрос. Какой бы алгоритм вы ни использовали, стоит разбить задачу. Сколько ядер / ЦП у вас есть? - person John La Rooy; 11.03.2010
comment
comment
Я видел решение, использующее fnmatch.fnmatch (). Вы знаете, как это семя может сравниваться? - person Vincent; 11.03.2010

Это намекает на самую длинную распространенную проблему подпоследовательности. Проблема схожести строк здесь в том, что вам нужно протестировать непрерывную строку из 230000 последовательностей; поэтому, если вы сравниваете одну из своих 25 последовательностей с непрерывной строкой, вы получите очень низкое сходство.

Если вы вычислите самую длинную общую подпоследовательность между вашими 25 последовательностями и непрерывной строкой, вы узнаете, есть ли она в строке, если длины одинаковы.

person Pierre-Antoine LaFayette    schedule 10.03.2010

Вы можете создать дерево из всех различных последовательностей, которые вы хотите сопоставить. Теперь сложная часть создания функции поиска в глубину по дереву, которая допускает не более одного несоответствия.

Преимущество этого метода в том, что вы просматриваете все последовательности сразу. Это избавит вас от множества сравнений. Например, когда вы начинаете с верхнего узла и спускаетесь по ветви «А», вы только что сохранили для себя много тысяч сравнений, потому что мгновенно сопоставили все последовательности, начинающиеся с «А». В качестве другого аргумента рассмотрим фрагмент генома, который точно соответствует заданной последовательности. Если у вас есть другая последовательность в вашем списке последовательностей, которая отличается только последним символом, то использование дерева только что спасло вам 23 операции сравнения.

Вот один из способов реализовать это. Преобразуйте 'A', 'C', T ', G' в 0,1,2,3 или его вариант. Затем используйте кортежи кортежей в качестве структуры для вашего дерева. В каждом узле первый элемент в вашем массиве соответствует букве «А», второй - букве «С» и так далее. Если «A» является ветвью этого узла, то есть еще один кортеж из 4 элементов в качестве первого элемента кортежа этого узла. Если нет ветви «A», то установите для первого элемента значение 0. Внизу дерева находятся узлы с идентификатором этой последовательности, чтобы ее можно было поместить в список совпадений.

Вот рекурсивные функции поиска, допускающие одно несоответствие для такого рода дерева:

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 означает, что несоответствия не было. В любом случае, я надеюсь, что я был достаточно ясен, чтобы вы поняли.

person Justin Peel    schedule 10.03.2010
comment
Забавно, но первое, что пришло мне в голову, было сделать дерево из всех 25 подстрок генома и сопоставить каждый кандидат с ним таким же образом. Для этого потребуется больше памяти. Я думаю, что ваш подход может быть еще более оптимизирован до обобщения сопоставления строк Aho-Corasick. - person Darius Bacon; 12.03.2010
comment
@Darius Да, я все еще думаю, что trie - очень хороший подход для этого. Я не думаю, что памяти будет слишком много, особенно если используется дерево с большей эффективностью памяти, такое как radix trie. Я выяснил, что в худшем случае будут посещены 925 узлов (с использованием базового дерева), чтобы найти все последовательности, соответствующие одному фрагменту генома. Средний случай намного меньше этого. Мне это кажется довольно быстрым. Придется взглянуть на алгоритм Ахо-Корасика. - person Justin Peel; 12.03.2010
comment
Совершенно верно - я имел в виду, что моему варианту ответа потребовалось бы намного больше памяти. Я проголосовал за это, это какая-то глупая ошибка StackOverflow, которая перевела мой голос на какой-то случайный другой ответ - это произошло раньше. Будем надеяться, что на этот раз потребуется. - person Darius Bacon; 12.03.2010
comment
Между прочим, идея с Aho-Corasick состоит в том, чтобы исследовать геном побайтно без резервного копирования, вместо того, чтобы исследовать его по одному 25-байтовому кадру за раз. Вы заранее компилируете конечный автомат, выполняя свои попытки, как если бы вы сопоставляли геном, только фактически еще не глядя на геном - вместо этого записывая тесты и состояния. - person Darius Bacon; 12.03.2010
comment
(Это было бы эквивалентно ответу gnibbler, за исключением того, что встроенная реализация регулярного выражения Python, по-видимому, не создает конечный автомат, а вместо этого выполняет возврат, поэтому он проигрывает в этой проблеме.) - person Darius Bacon; 12.03.2010

Я пробовал некоторые решения, но, как уже было написано, они работают медленно при работе с большим количеством последовательностей (строк).

Я придумал использовать bowtie и сопоставить интересующую подстроку (soi) со справочным файлом, который содержит строки в формате FASTA. Вы можете указать количество допустимых несовпадений (0..3) и получить обратно строки, которым сопоставлена ​​soi с учетом разрешенных несоответствий. Это работает хорошо и довольно быстро.

person sebastian.boegel    schedule 07.02.2012

Вы можете использовать встроенную возможность Pythons для поиска с сопоставлением регулярных выражений.

re в модуле python http://docs.python.org/library/re.html

праймер регулярных выражений http://www.regular-expressions.info/

person Daniel    schedule 10.03.2010

Думаю, это может произойти немного поздно, но есть инструмент под названием PatMaN, который делает именно то, что вы хотите: http://bioinf.eva.mpg.de/patman/

person cpp1    schedule 27.05.2010

Вы можете использовать библиотеку сопоставления регулярных выражений TRE для «приблизительного сопоставления». Он также имеет привязки для Python, Perl и Haskell.

import tre

pt = tre.compile("Don(ald)?( Ervin)? Knuth", tre.EXTENDED)
data = """
In addition to fundamental contributions in several branches of
theoretical computer science, Donnald Erwin Kuth is the creator of
the TeX computer typesetting system, the related METAFONT font
definition language and rendering system, and the Computer Modern
family of typefaces.
"""

fz = tre.Fuzzyness(maxerr = 3)
print fz
m = pt.search(data, fz)

if m:
    print m.groups()
    print m[0]

который будет выводить

tre.Fuzzyness(delcost=1,inscost=1,maxcost=2147483647,subcost=1, maxdel=2147483647,maxerr=3,maxins=2147483647,maxsub=2147483647)
((95, 113), (99, 108), (102, 108))
Donnald Erwin Kuth

http://en.wikipedia.org/wiki/TRE_%28computing%29

http://laurikari.net/tre/

person sefakilic    schedule 11.06.2012

Мне показалось, что приведенный ниже код простой и удобный.

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

Вы можете легко вставить геномы и сегменты, которые хотите проверить, а также установить значение несовпадения.

person nosense    schedule 30.01.2016