Python Regex-计算短串联重复的最大数量

Python Regex-计算短串联重复的最大数量,python,regex,bioinformatics,Python,Regex,Bioinformatics,我在一系列短串联重复序列中循环,试图找到它们在DNA序列中连续出现的最大次数 顺序: AAGGTAAGTTTAGAATATAAAAGGTGAGTTAAATAGAATAGGTTAAAATTAAAGGAGATCAGATCAGATCAGATCTATCTATCTATCTATCTATCAGAAAAGAGAGATCAGATCAGTTAAAGAGTAAGATATTGAATTAATGGAAAATATTGTTGGGGAAAGGAGGGATAGAGATCAGATC STRs=['AGATC','AATG','TA

我在一系列短串联重复序列中循环,试图找到它们在DNA序列中连续出现的最大次数

顺序:

AAGGTAAGTTTAGAATATAAAAGGTGAGTTAAATAGAATAGGTTAAAATTAAAGGAGATCAGATCAGATCAGATCTATCTATCTATCTATCTATCAGAAAAGAGAGATCAGATCAGTTAAAGAGTAAGATATTGAATTAATGGAAAATATTGTTGGGGAAAGGAGGGATAGAGATCAGATC
STRs=['AGATC','AATG','TATC']
对于STR中的STR:

max_repeats=len(re.findall(f’(?要查找AGATC的所有序列,只要它不在序列的末尾,您可以使用:

>关于findall(r'AGATC\B',序列)
['AGATC'、'AGATC'、'AGATC'、'AGATC']
发件人:

匹配空字符串,但仅当它不在单词的开头或结尾时才匹配。这意味着
r'py\B'
匹配
'python'
'py3'
'py2'
,但不匹配
'py'
/py'
'py!'
\B
,因此Unic中的单词字符ode模式是Unicode字母数字或下划线,尽管这可以通过使用
ASCII
标志进行更改。如果使用
locale
标志,则单词边界由当前语言环境确定


这里有一种解决问题的方法:

>>> STRs = ['AGATC', 'AATG', 'TATC']
>>> pattern = '|'.join(f'({tgt})+' for tgt in STRs)
>>> for mo in re.finditer(pattern, seq):
         print(mo.group(0))

AGATCAGATCAGATCAGATC
TATCTATCTATCTATCTATC
AGATCAGATC
AATG
AGATCAGATC
>>> tracker = dict.fromkeys(STRs, 0)
>>> for mo in re.finditer(pattern, seq):
        start, end = mo.span()
        STR = next(filter(None, mo.groups()))
        reps = (end - start) // len(STR)
        tracker[STR] = max(tracker[STR], reps)

>>> tracker
{'AGATC': 4, 'AATG': 1, 'TATC': 5}
关键理念:

>>> STRs = ['AGATC', 'AATG', 'TATC']
>>> pattern = '|'.join(f'({tgt})+' for tgt in STRs)
>>> for mo in re.finditer(pattern, seq):
         print(mo.group(0))

AGATCAGATCAGATCAGATC
TATCTATCTATCTATCTATC
AGATCAGATC
AATG
AGATCAGATC
>>> tracker = dict.fromkeys(STRs, 0)
>>> for mo in re.finditer(pattern, seq):
        start, end = mo.span()
        STR = next(filter(None, mo.groups()))
        reps = (end - start) // len(STR)
        tracker[STR] = max(tracker[STR], reps)

>>> tracker
{'AGATC': 4, 'AATG': 1, 'TATC': 5}
1) 用于组的核心模式,允许连续重复:

(AGATC)+
2) 模式与
|
组合,以允许任何STR匹配:

>>> pattern
'(AGATC)+|(AATG)+|(TATC)+'
3) finditer()调用一次提供一个匹配对象

4) 如果需要,match对象可以提供其他信息,如计算长度的起始点和停止点,或显示匹配的STR的元组:

>>> mo.group(0)
'AGATCAGATC'
>>> mo.span()
(171, 181)
>>> mo.groups()
('AGATC', None, None)
如何计算最大重复次数:

>>> STRs = ['AGATC', 'AATG', 'TATC']
>>> pattern = '|'.join(f'({tgt})+' for tgt in STRs)
>>> for mo in re.finditer(pattern, seq):
         print(mo.group(0))

AGATCAGATCAGATCAGATC
TATCTATCTATCTATCTATC
AGATCAGATC
AATG
AGATCAGATC
>>> tracker = dict.fromkeys(STRs, 0)
>>> for mo in re.finditer(pattern, seq):
        start, end = mo.span()
        STR = next(filter(None, mo.groups()))
        reps = (end - start) // len(STR)
        tracker[STR] = max(tracker[STR], reps)

>>> tracker
{'AGATC': 4, 'AATG': 1, 'TATC': 5}

这是一种函数式编程方法。在每个递归步骤中,找到连续重复的第一次出现,然后从搜索字符串中删除。您将记录到目前为止找到的最大重复次数,并将其传递给每个递归调用,直到再也找不到连续重复为止

def find_repeats (pattern, seq, max_r=0):
    g = re.search(f'{pattern}({pattern})+', seq)
    if g:
        max_repeats = len ( g.group() ) / len(pattern)
        return find_repeats (pattern, seq.replace (g.group(), '', 1), max (max_r, max_repeats) )
    else:
        return max_r

print (find_repeats ('AGATC', sequence))

当您正在搜索的字符串中没有动态内容时,尤其是当您正在搜索的字符串很大时,我会尝试找到一种避免正则表达式的解决方案,因为基本字符串方法通常比正则表达式快得多

以下内容可能在很多方面都不符合Pythonic(欢迎改进建议),但基本假设是
str.split()
的性能大大优于regex,并且计算字符串位置的算法花费的时间可以忽略不计

def find_tandem_repeats(sequence, search):
    """ searches through an DNA sequence and returns (position, repeats) tuples """
    if sequence == '' or search == '':
        return

    lengths = list(map(len, sequence.split(search)))
    pos = lengths[0]
    repeats = 0
    pending = False

    for l in lengths[1:]:
        if l == 0:
            pending = True
            repeats += 1
            continue
        repeats += 1
        yield (pos, repeats)
        pos += l + len(search) * repeats
        repeats = 0
        pending = False

    if pending:
        yield (pos, repeats)
用法:

data = "AAGGTAAGTTTAGAATATAAAAGGTGAGTTAAATAGAATAGGTTAAAATTAAAGGAGATCAGATCAGATCAGATCTATCTATCTATCTATCTATCAGAAAAGAGAGATCAGATCAGTTAAAGAGTAAGATATTGAATTAATGGAAAATATTGTTGGGGAAAGGAGGGATAGAGATCAGATC"
positions = list(find_tandem_repeats(data, 'AGATC'))

for position in positions:
    print("at index %s, repeats %s times" % position)

max_position = max(positions, key=lambda x: x[1])
print("maximum at index %s, repeats %s times" % max_position)
输出

at index 55, repeats 4 times at index 104, repeats 2 times at index 171, repeats 2 times maximum at index 55, repeats 4 times 在索引55处,重复4次 在索引104处,重复2次 在索引171处,重复2次 索引55处的最大值,重复4次
你的回答让我意识到我的问题措辞糟糕,抱歉!我实际上是想从序列中获取最大数量的重复,我编辑了我的帖子来反映这一点
\B
正确匹配重复序列,这比我原来的正则表达式好得多,但现在我遇到了一个问题,即在我得到7个STR的列表时,隔离最大数量的连续重复,它包括开始时的4次重复+中间的2次重复+最后的1次,这似乎能很好地隔离重复序列,但是,从输出匹配对象中查找每个STR的最大重复次数的最佳方法是什么,因为它们没有存储在像
re.findall
@kish这样的列表中。kish可以在字典中保留一个连续的重复次数,并在循环过程中进行更新。
max(len(x[0])//len len x(x[1])对于re.findall(r'((ab | bc 2+)中的x“,”ababababcbcabab'))
是一个这样做的原型,我准备了一个类似的答案,但花了太长时间…@kish an我扩展了答案,展示了如何累积最大大小。我没有意识到字符串方法比正则表达式快,我认为正则表达式的唯一目的是在文本中找到模式,因此将为此进行优化。很多正则表达式的答案我都想不通,但至少我可以开始理解这一点,如果我逐行检查代码的话。是的,这是正则表达式的唯一目的。但是regex做的工作比拆分字符串的简单循环多得多。正则表达式的速度要慢得多,值得做一个比较,尤其是在大的输入大小上。简单的字符串操作找不到模式,但你没有模式——你有子字符串。@kish-an无论如何,做一个比较,不要把我当作我的单词。另外,我只在短字符串上测试了几个简单的例子,请在实际数据上进行彻底的测试。我之所以选择
str.split()
而不是
str.index()
上的循环,是因为
split
是一个完全在C代码中运行且高度优化的单个调用<代码>索引
需要多次调用才能到达字符串末尾。
split
的缺点是它为返回的部分分配内存,这些部分基本上会立即被丢弃
index
理论上可以在同一个字符串实例上运行,而不需要分配新内存。这对于在同一输入字符串上进行多个搜索可能是有益的。啊,我明白了,这里的优势肯定是性能而不是内存,但我认为将其与正则表达式解决方案进行比较会很有趣。我感谢所有的帮助!