Многочисленные несоответствия в регулярном выражении поиска ДНК - PullRequest
1 голос
/ 14 декабря 2011

Я написал этот варварский скрипт для создания перестановок строки символов, которые содержат n (до n = 4) $ во всех возможных комбинациях позиций в строке.Я в конечном итоге .replace('$','(\\w)') использовать для несоответствий в последовательности поиска ДНК.Из-за того, как я написал скрипт, у некоторых перестановок меньше запрошенного числа $.Затем я написал скрипт для их удаления, но он не кажется эффективным, и каждый раз, когда я запускаю скрипт удаления, он удаляет все больше нежелательных перестановок.В приведенном ниже коде вы увидите, что я тестирую функцию с простой последовательностью с 4 несоответствиями.Затем я запускаю серию сценариев удаления, которые подсчитывают, сколько выражений удаляется каждый раз ... По моему опыту, для удаления всех выражений с менее чем 4 подстановочными знаками $ требуется около 8 раз.У меня есть пара вопросов по этому поводу:

  1. Есть ли встроенная функция для поиска с несоответствиями 'n'?Может быть, даже в биопионе?До сих пор я видел функцию Paul_McGuire_regex:
    Поиск строки, допускающей одно несоответствие в любом месте строки ,
    , которая, кажется, генерирует только 1 несоответствие.Должен признать, я не до конца понимаю весь код оставшихся функций на этой странице, так как я очень новый кодер.

  2. Поскольку я считаю это хорошим упражнениемдля меня, есть ли лучший способ написать весь этот сценарий? ... Могу ли я повторять функцию Paul_McGuire_regex столько раз, сколько мне нужно?

  3. Наиболее озадачивает меня, почему бы несценарий удаления работает в первый раз на 100%?

Спасибо за любую помощь, которую вы можете оказать!

def Mismatch(Search,n):
    List = []
    SearchL = list(Search)
    if n > 4:
        return("Error: Maximum of 4 mismatches")
    for i in range(0,len(Search)):
        if n == 1:
            SearchL_i = list(Search)
            SearchL_i[i] = '$'
            List.append(''.join(SearchL_i))
        if n > 1:
            for j in range (0,len(Search)):
                if n == 2:
                    SearchL_j = list(Search)
                    SearchL_j[i] = '$'
                    SearchL_j[j] = '$'
                    List.append(''.join(SearchL_j))
                if n > 2:
                    for k in range(0,len(Search)):
                        if n == 3:
                            SearchL_k = list(Search)
                            SearchL_k[i] = '$'
                            SearchL_k[j] = '$'
                            SearchL_k[k] = '$'
                            List.append(''.join(SearchL_k))
                        if n > 3:
                            for l in range(0,len(Search)):
                                if n ==4:
                                    SearchL_l = list(Search)
                                    SearchL_l[i] = '$'
                                    SearchL_l[j] = '$'
                                    SearchL_l[k] = '$'
                                    SearchL_l[l] = '$'
                                    List.append(''.join(SearchL_l))
    counter=0
    for el in List:
        if el.count('$') < n:
            counter+=1
            List.remove(el)
    return(List) 

List_RE = Mismatch('abcde',4)

counter = 0
for el in List_RE:
    if el.count('$') < 4:
        List_RE.remove(el)
        counter+=1

print("Filter2="+str(counter))

1 Ответ

3 голосов
/ 15 декабря 2011

Мы можем покончить с вопросами 2 и 3, ответив на вопрос 1, но понимание вопроса 3 важно, поэтому сначала я сделаю это, а затем покажу, как можно полностью избежать этого:

Вопрос 3

Что касается вопроса 3, то это потому, что когда вы перебираете список в python и вносите в него изменения в цикле , список, над которым вы зацикливаетесь, меняется.

Из документов python о потоке управления (для секции операторов) :

небезопасно изменять последовательность, повторяемую в цикле (это может происходить только для типов изменяемых последовательностей, таких как списки).

Скажите, что ваш список [a,b,c,d], и вы просматриваете его с помощью for el in List. Скажите el в настоящее время a, а вы List.remove(el).

Теперь ваш список [b,c,d]. Тем не менее, итератор указывает на второй элемент в списке (так как он сделал первый), который теперь c. По сути, вы пропустили b. Так что проблема в том, что вы модифицируете список, по которому вы перебираете.

Есть несколько способов исправить это: если ваш List не является дорогостоящим для копирования, вы можете сделать копию. Так итерируйте по List[:], но удалите из List.

Но предположим, что постоянно делать копии List дорого. Тогда вы делаете итерацию по ней назад . Обратите внимание на reversed ниже:

for el in reversed(List):
    if el.count('$') < n:
        counter+=1
        List.remove(el)
return(List) 

В приведенном выше примере предположим, что мы повторяем в обратном направлении по List. Итератор начинается с d, а затем переходит к c. Предположим, мы удалили c, так что List=[a,b,d]. Поскольку итератор движется назад , теперь он указывает на элемент b, поэтому мы ничего не пропустили.

По сути, это позволяет избежать изменения битов списка, который вам еще предстоит перебрать.

Вопросы 1 и 2

Если я правильно понимаю ваш вопрос, вы, в основном, хотите выбрать n из m позиций, где m - длина строки (abcde), и поставить '$' в каждом из эти n позиции.

В этом случае вы можете использовать для этого модуль itertools.

import itertools
def Mismatch(Search,n):
    SearchL = list(Search)
    List     = [] # hold output
    # print list of indices to replace with '$'
    idxs = itertools.combinations(range(len(SearchL)),n)        
    # for each combination `idx` in idxs, replace str[idx] with '$':
    for idx in idxs:
        str = SearchL[:] # make a copy
        for i in idx:
            str[i]='$'
        List.append( ''.join(str) ) # convert back to string
    return List

Давайте посмотрим, как это работает:

  1. превратить строку Search в список, чтобы ее можно было перебрать, создать пустое List для хранения результатов.
  2. idxs = itertools.combinations(range(len(SearchL)),n) говорит "найти все подмножества длины n в наборе [0,1,2,3,...,length-of-search-string -1]. Попробуйте

    idxs = itertools.combinations(range(5),4)
    for idx in idxs: 
        print idx
    

    чтобы понять, что я имею в виду.

  3. Каждый элемент idxs является кортежем n индексов от 0 до len(SearchL)-1 (например, (0,1,2,4). Замените i-й символ SearchL на '$' для каждого i в кортеж.
  4. Преобразовать результат обратно в строку и добавить его к List.

Как пример:

Mismatch('abcde',3)
['$$$de', '$$c$e', '$$cd$', '$b$$e', '$b$d$', '$bc$$', 'a$$$e', 'a$$d$', 'a$c$$', 'ab$$$']
Mismatch('abcde',4) # note, the code you had made lots of duplicates.
['$$$$e', '$$$d$', '$$c$$', '$b$$$', 'a$$$$'] 
...