I develop an algorithm to find the most common substrings of a given length n up to a certain distance l in front of a pattern p in a huge sequence S. E.g. I want to find the most common hexamers (substring of length 6) that occur in front of the string pattern p="TTAA" at a distance of at most l=1000 characters in front of the pattern "TTAA" in S. The steps of the algorithm are:
- Import the sequence S.
- Detect the first positions i∈{1,...,k} of all occurrences of pattern p in S.
- Extract the sites (substrings) si in front of each pattern position i from S.
- Determine all nmers (substrings of length n) for each site si.
- Select the nmer from all those substrings that is the most common and determine how many sites can be covered with that nmer.
- Delete the lists that are covered.
- Repeat 5. and 6. until all lists are covered or stop after a given number of iterations.
The result should be a list of the nmers that are the most common ones in decending order of coverage.
Consider this string for the variable sequence and the following code. I first determine the positions in S where the pattern p occurs:
sequence = StringTake[Import["http://ge.tt/api/1/files/9teGemr/1/blob?download"], 200000];
pattern = "TTAA";
positions = StringPosition[sequence, pattern, IgnoreCase -> True];
Now I want to extract all the substrings si of length 1000 characters in front of the pattern p that appears at position i in sequence. In principle, I already have a solution for the problem but it appears to be quite slow if S is large and the pattern matches many positions (many si have to be extracted):
substrings = Table[
If[
First[i] < 1001,
StringTake[sequence, {1, First[i]-1}],
StringTake[sequence, {First[i] - 1001, First[i] - 1}]
], {i, positions}
];
For the runtime I have added some tests here without (left) and with (right) parallelization (ParallelTable instead of Table):
However, as soon as the number of found positions for the pattern and the length of the sequence increases the runtime of this approach explodes. For example if I run the code for the whole sequence of 1 million characters without (left) and with (right) parallelization (ParallelTable instead of Table):
Is there a faster way to do this?
Edit 17/03/2014
The code proposed by Öskå is a little bit faster, but still I would need this code to run for much longer sequences (200 million characters) and many more hits (about 3 million).
Edit 18/03/2014
The code proposed by Leonid Shifrin seems to be a hell of a fast piece of code :) I tested it for a sequence of 20 million characters and got the following results:
The code proposed by george2079 achieves:
@LeonidShifrin comment:
By the way, for 200 million chars and a few million hits, you'll really need some lazy infrastructure, because just holding all your extracted substrings in RAM at the same time won't be possible for such large objects. Are you interested in this kind of solution?
Yes indeed, I already thought about this. Later on, each extracted si has to be splitted into overlapping substrings of length 6. I currently do this using Partition
on the list of characters. My idea was to dump save each of those strings si into an MX
file and then move on file by file:
ParallelTable[
(
cur = FromCharacterCode /@
Partition[ToCharacterCode[sites[[i]]], nSize, 1];
Export[FileNameJoin[{path,
"hexamers-site-" <>
StringJoin[ToString /@ (PadLeft[IntegerDigits[i], 9, 0])] <>
".mx"}], cur]
), {i, 1, Length@sites}]