简体   繁体   中英

Python find longest ORF in DNA sequence

Can someone show me a straightforward solution for how to calculate the longest open reading frame (ORF) in a DNA sequence? ATG is the start codon (ie, the beginning of an ORF) and TAG , TGA , and TAA are stop codons (ie, the end of an ORF).

Here's some code that produces errors (and uses an external module called BioPython):

import sys
from Bio import SeqIO

currentCid = ''
buffer = []

for record in SeqIO.parse(open(sys.argv[1]),"fasta"):
    cid = str(record.description).split('.')[0][1:]

    if currentCid == '':
        currentCid = cid
    else:
        if cid != currentCid:
            buffer.sort(key = lambda x : len(x[1]))
            print '>' + buffer[-1][0]
            print buffer[-1][1]
            currentCid = cid
            buffer = [(str(record.description),str(record.seq))]
        else:
            buffer.append((str(record.description),str(record.seq)))

buffer.sort(key = lambda x : len(x[1]))
print '>' + buffer[-1][0]
print buffer[-1][1]

Is it possible to write this procedure with the least amount of external dependencies (or at least get the above code to work)?

Here's what my input looks like:

ACCGCCGCGAACATCGCCGAGATCCTGCCGCCGCAGCCGAGCCGGCTGGTCGAGTATGCGCAACGACGCG
CGTCCGGCAGCATCCCGGCGATCATGGCGCGCTGGGATGCACGCGTACTGCAGGACAACGAACCATTCAC
CGCAGTCTATGGCGGCGCGTCGTACATCAACAACGACCTGTTCCTCGCCCGCCTCGCCGACTGGGGCGTG
TCGGCCGGCAACTACAGCGGCGAGATCGGCGGCGCGACACCGCCGCTGCGCTGGCGCCCGCTGCGGCTGC
TGCGTTCGCTGCCGGTGTTCTGGCGCATGCTGCGTGTCGCGCGCGGGCACCTGCCGACGCTCGAGCGCGG
CTTGCAGCGCTTCGACCAGGAACTCGCGACGCTCGTCGAGCGACGCGCCGACGGCCAGCAACTGGCCGAC
TGGTTCACGCGCTTCTACGTGTTCGTCGTGCAGGGCAACCTGTGCATCGCGTCGTCGCTGGCCAGCAGCG
GCGGCGCACTGTGGGGCCGTCCGCCGACCGCATACGGCCAGCTCGACGACAGCCCGCACCGGCTGCCGTG
GGAAACCGATCCGGGCACCGCACGGCCCGCGCCCACCCACCTGCCGCTGCAGGCGTTTCCCGCCTGGCCG
CTGCCGGTCCGCGTGCTCCACGCGCTCGGCGCGCCCGGCATGCGCGGCTGGTATCTGCAGGTGCGCGAGT
GGTATCGCGACAACCTGATGCGCGTGTTCTTCCGCCTGCATCATGCGATGCCGGCCGCCGATCGCGACAC
GTGGTTCGCGCCCCATCCCGATCGCCGCGAACGCAACGGCAGCTTCTGGCAGGACGGCGGCGAAGGCACC
GACGAGGCAGCCGGCTTCATGATCTATCCGGGCCACACGCAAGGCGTGCTCGGCCACGACATCCTGCTGG
AAGACACGCTCGACCCGGGCCGGCACGCGCAGTACCAGGCCGCGCGCGCCGTGATCGCGCGCATGGGCGG
CCGGCTGTCGCACGGCGCGACGCTGCTGCGCGAGCTGCGCAAGCCGTCGGCCGTGCTGCCGCGCGTCGAT
GCGGCGTGGATCGGGCGCGAGGTGCGGCTCAGCGACGGCCAGCTGACGCTGGTCGAATGAACGCGATGCG
GTTGCCGCGCACCCGAGCACGGGCCCGGGCCTGAACTGCCGATCAGCGTACCGGCGTGCGGACGACTCCG
TCGACCTTCAGCGTGCGCCGGTCGTGCGCGGCTTCGTATTCGACCGTCTGCGCAGGCGTGACGGCGCCGT
ATGAATGGCCGTTCACGTAGACGGTGCCGTCCCGCAGCTCGACCCGGTCGCCGTTGACCGTCGCTGTGGC
CCGTTCACCCTGCAGCACCGCGCCCGAACAACCTGCAGTCGAAAAACTGCGGACCGACGTGCCCGGCATC
GCGGCGATCCCGCCCTGGTCCGCCGCATGCGCCGCGCTGCACGGCGGCGCATCCATGCTGCCGGCAGCGT
GGACCGCGCCGGCGCTGATGCCGCATCCGGCAAGCAGCGCAATCGTCATCGGCTTCAGATGGTTCATGGT
GAGCTCCGTTGTCCGCCGCCGCGGATCGATGACCGGCCGACGCCCGTGCTCGCATGGCAGGCCGGCCGGC
CGGATGCATCCAGTATGCGTCCGGTTCGCGGCATTCCGCCATCGTCGCCGATACCGCTCATCGCCGCCCG
GTTCGCTCCCGCAGCGGCCTCTGGAAGCACCTCCCGCGGGGCAACCCGTCCCCATGAAAATCCACCTTGA
TCAAGTTGCGACTCGCAACTATTATTGATTGCGATCCGCAACCTTTCCGGACCCGCCATGGACCTCATCG
ACGCTCCCGCCAAGCCCCGCGAAGCCACGATCCTCGAGCTGCGCGACTTCTCCCGCAAACTGGTTCGCGA
GCTCGGCTTCATGCGCGCGACGCTGGCCGACAGCGACTGGGCGCCTT

My output should be:

The longest substring that begins with ATG (ie, the start of an ORF) and ends with either TAG , TGA , or TAA as stop codons (ie, the end of an ORF).

You should look into regular expressions:

import re

max(re.findall(r'ATG(?:(?!TAA|TAG|TGA)...)*(?:TAA|TAG|TGA)',s), key = len)

There is a good tutorial here , that focuses on the use of regular expressions with DNA strings

Since BioPython is a well-established and widely available module that's specifically designed for these sorts of questions, there's little reason to avoid it and re-invent the wheel. That said it is useful to use regexes to identify start codons:

from Bio import Seq
import regex as re
startP = re.compile('ATG')
nuc = input_seq.replace('\n','')
longest = (0,)
for m in startP.finditer(nuc, overlapped=True):
    if len(Seq.Seq(nuc)[m.start():].translate(to_stop=True)) > longest[0]:
        pro = Seq.Seq(nuc)[m.start():].translate(to_stop=True)
        longest = (len(pro), 
                   m.start(), 
                   str(pro),
                   nuc[m.start():m.start()+len(pro)*3+3])

Note that this uses the regex module, not the re module; the former allows easier identification of overlapping matches. We can let BioPython count triplets and look for stop codons, rather than try to labor through regexes to do that.

Here, longest yields the length of the protein encoded by the ORF, the start site (note, using 0-based numbering), the protein sequence encoded by the ORF, and the sequence of the ORF itself, including the stop codon.

(338,
 93,
 'MARWDARVLQDNEPFTAVYGGASYINNDLFLARLADWGVSAGNYSGEIGGATPPLRWRPLRLLRSLPVFWRMLRVARGHLPTLERGLQRFDQELATLVERRADGQQLADWFTRFYVFVVQGNLCIASSLASSGGALWGRPPTAYGQLDDSPHRLPWETDPGTARPAPTHLPLQAFPAWPLPVRVLHALGAPGMRGWYLQVREWYRDNLMRVFFRLHHAMPAADRDTWFAPHPDRRERNGSFWQDGGEGTDEAAGFMIYPGHTQGVLGHDILLEDTLDPGRHAQYQAARAVIARMGGRLSHGATLLRELRKPSAVLPRVDAAWIGREVRLSDGQLTLVE',
 'ATGGCGCGCTGGGATGCACGCGTACTGCAGGACAACGAACCATTCACCGCAGTCTATGGCGGCGCGTCGTACATCAACAACGACCTGTTCCTCGCCCGCCTCGCCGACTGGGGCGTGTCGGCCGGCAACTACAGCGGCGAGATCGGCGGCGCGACACCGCCGCTGCGCTGGCGCCCGCTGCGGCTGCTGCGTTCGCTGCCGGTGTTCTGGCGCATGCTGCGTGTCGCGCGCGGGCACCTGCCGACGCTCGAGCGCGGCTTGCAGCGCTTCGACCAGGAACTCGCGACGCTCGTCGAGCGACGCGCCGACGGCCAGCAACTGGCCGACTGGTTCACGCGCTTCTACGTGTTCGTCGTGCAGGGCAACCTGTGCATCGCGTCGTCGCTGGCCAGCAGCGGCGGCGCACTGTGGGGCCGTCCGCCGACCGCATACGGCCAGCTCGACGACAGCCCGCACCGGCTGCCGTGGGAAACCGATCCGGGCACCGCACGGCCCGCGCCCACCCACCTGCCGCTGCAGGCGTTTCCCGCCTGGCCGCTGCCGGTCCGCGTGCTCCACGCGCTCGGCGCGCCCGGCATGCGCGGCTGGTATCTGCAGGTGCGCGAGTGGTATCGCGACAACCTGATGCGCGTGTTCTTCCGCCTGCATCATGCGATGCCGGCCGCCGATCGCGACACGTGGTTCGCGCCCCATCCCGATCGCCGCGAACGCAACGGCAGCTTCTGGCAGGACGGCGGCGAAGGCACCGACGAGGCAGCCGGCTTCATGATCTATCCGGGCCACACGCAAGGCGTGCTCGGCCACGACATCCTGCTGGAAGACACGCTCGACCCGGGCCGGCACGCGCAGTACCAGGCCGCGCGCGCCGTGATCGCGCGCATGGGCGGCCGGCTGTCGCACGGCGCGACGCTGCTGCGCGAGCTGCGCAAGCCGTCGGCCGTGCTGCCGCGCGTCGATGCGGCGTGGATCGGGCGCGAGGTGCGGCTCAGCGACGGCCAGCTGACGCTGGTCGAATGA')

Check this out:

https://www.kaggle.com/xiangma/orf-finder?scriptVersionId=6709465

As shown in the link above, there are two methods to do this:

Please note I set ORF length limitation above 1000bp and you can adjust it with your needs.

First one:

from Bio import SeqIO
records = SeqIO.parse('dna2.fasta', 'fasta')
for record in records:
    for strand, seq in (1, record.seq), (-1, record.seq.reverse_complement()):
        for frame in range(3):
            length = 3 * ((len(seq)-frame) // 3)
            for pro in seq[frame:frame+length].translate(table = 1).split("*")[:-1]:
                if 'M' in pro:
                    orf = pro[pro.find('M'):]
                    pos = seq[frame:frame+length].translate(table=1).find(orf)*3 + frame +1
                    if len(orf)*3 +3 > 1300:
                        print("{}...{} - length {}, strand {}, frame {}, pos {}, name {}".format\
                           (orf[:3], orf[-3:], len(orf)*3+3, strand, frame, pos, record.id))

Second one, which uses the regex:

from Bio import SeqIO
import re
records = SeqIO.parse('dna2.fasta', 'fasta')

for record in records:
    for strand, seq in (1, record.seq), (-1, record.seq.reverse_complement()):
        for frame in range(3):
            index = frame
            while index < len(record) - 6:
                match = re.match('(ATG(?:\S{3})*?T(?:AG|AA|GA))', str(seq[index:]))
                if match:
                    orf = match.group()
                    index += len(orf)
                    if len(orf) > 1300:
                        pos = str(record.seq).find(orf) + 1 
                        print("{}...{} - length {}, strand {}, frame {}, pos {}, name {}".format\
                           (orf[:6], orf[-3:], len(orf), strand, frame, pos, record.id))
                else: index += 3

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM