I am trying to solve a bioinformatics problems from a Stepic course.
The problem posed: find clumps of the same pattern within a longer genome.
Motivation: Identifying 3 occurrences of the same pattern within a window of length 500 within a genome allows biologists to find the "replication origin" of a bacterial genome. This replication origin is required for the bacteria to clone itself, and it is therefore significant.
Using Python, I have written a solution that works effectively for small, test data sets, but which is not efficient for real-life genomes. Below I describe the method used.
I've used two core functions.
patternOccurances
This function finds all the starting locations of a short pattern in a longer string.
def patternOccurances2(text="GATATATGCATATACTT", pattern="ATAT"):
occurances = []
position = -1
position = config.genome.find(pattern, position+1)
occurances.append(position)
while position != -1:
position = text.find(pattern, position+1)
occurances.append(position)
return occurances[:-1]
frequentPatterns
This second function finds all patterns of length k
in a string that occur at least t
times; or, if t
is omitted, only the most frequent patterns of length k
.
def frequentPatterns(text="", k=2,numberOfOccurances=None):
#Frequent Words Problem: Find the frequent k-mers in a string.
# Input: A string text, and an integer k, number of occurances t
# Output: All most frequent k-mers in Text.
words = {}
frequentPatterns = []
#create a dictionary of all patterns of length k in text with their respective frequencies
for i in range(len(text)-k + 1): #iterate over the valid length of the string
a = text[i:i+k]
if a in words:
words[a] = words[a] + 1
else:
words[a] = 1
if numberOfOccurances == None: #gives only the most frequent strings of length k
largestValue=0
for k, v in words.iteritems():
if v > largestValue:
frequentPatterns = []
frequentPatterns.append(k)
largestValue = v
if v == largestValue:
frequentPatterns.append(k)
else: #gives all strings of length k that occur numberOfOccurances times
for k, v in words.iteritems():
if v >= numberOfOccurances:
frequentPatterns.append(k)
return frequentPatterns
Main Code
The main code calls the above functions as follows:
#Clump Finding Problem: Find patterns forming clumps in a string.
# Input: A long string Genome, and integers k, L, and t.
# k is the length of the pattern we wish to match.
# t is the minimum number of times we wish to find this pattern in a portion of length L in the Genome.
# Output: All distinct k-mers forming (L, t)-clumps in Genome.
f = open("E-coli.txt",'r') #input from a large file, 4.2MB
genome = f.read()
k = 9
L = 500
t = 3
#find all patterns of length k in genome that occur at least t times
frequentPatterns = ex213.frequentPatterns(text=genome,k=k,numberOfOccurances=t)
#for each pattern in frequentPatterns, find the locations of the patterns in the genome
#then find if any 3 of these patterns are within distance L of each other
for pattern in frequentPatterns:
locations = ex322.patternOccurances("",pattern)
for location in range(len(locations) - 2):
if locations[location + 1] - locations[location] <= L:
if locations[location + 2] - locations[location] <= L:
print pattern #3 of the pattern are sufficiently close to each other
break
f.close()
Main Code Performance
Measurements show that the frequentPatterns
call completes quickly. This call only occurs once, and therefore optimising it will not significantly improve the speed of the code.
However, the outer for loop takes a great deal of time to complete (in the order of several hours). In particular, the patternOccurances
call is particularly slow. However, I am sure other inefficiencies exist in the code.
Other programmers have completed the same task within 40s.
- How can my coding be improved?
- How can I optimise my algorithms performance?
- Do more efficient algorithms exist?
For those interested, the large dataset for which the above algorithms should efficiently work can be found here (4.2MB).
patternOccurances
function won't work properly: it doesn't check patterns beginning at the first character. And for the rest, you may want to take a look atCounter
fromcollections
. \$\endgroup\$