增加字符串重叠矩阵构建效率

时间:2014-03-02 21:15:26

标签: c++ performance dna-sequence

我有一个巨大的列表(N = ~1百万)字符串长100个字符,我正试图找到它们之间的重叠。例如,一个字符串可能是

XXXXXXXXXXXXXXXXXXAACTGCXAACTGGAAXA (and so on)

我需要构建一个N×N矩阵,其中包含每个字符串与每个其他字符串的最长重叠值。我目前的方法是(伪代码)

  

将所有字符串读入数组

     

创建空的NxN矩阵

     

将每个字符串与具有更高数组索引的每个字符串进行比较(以避免重做比较)

     

将最长重叠写入矩阵

还有很多其他的东西在继续,但我真的需要一种更有效的方法来构建矩阵。即使拥有最强大的计算集群,我也能掌握这种方法需要几天时间。

如果您没猜到,这些是DNA片段。 X表示“通配符”(探针低于阈值质量得分),所有其他选项是基础(A,C,T或G)。我尝试编写一个四元树算法,但这种方法太过密集了。

我喜欢你能提出的更有效方法的建议;我正在使用C ++,但伪代码/想法或其他语言代码也非常有用。

编辑:一些代码摘录,说明了我当前的方法。任何与概念无关的内容都已被删除

//part that compares them all to each other
for (int j=0; j<counter; j++) //counter holds # of DNA
    for (int k=j+1; k<counter; k++)
        int test = determineBestOverlap(DNArray[j],DNArray[k]);

//boring stuff

//part that compares strings. Definitely very inefficient,
//although I think the sheer number of comparisons is the main problem
int determineBestOverlap(string str1, string str2)
{
    int maxCounter = 0, bestOffset = 0;
    //basically just tries overlapping the strings every possible way
    for (int j=0; j<str2.length(); j++)
    {
        int counter = 0, offset = 0;
        while (str1[offset] == str2[j+offset] && str1[offset] != 'X') 
        {
              counter++;
              offset++;
        }

        if (counter > maxCounter)
        {
                    maxCounter = counter;
                    bestOffset = j;
        }
    }
    return maxCounter; 
} //this simplified version doesn't account for flipped strings

2 个答案:

答案 0 :(得分:1)

你真的需要知道所有字符串对之间的匹配吗?如果是,那么你必须将每个字符串与每个其他字符串进行比较,这意味着你需要进行n ^ 2/2比较,即使每个字符串对只存储一个字节,你也需要一个半TB的内存。

但是,我假设你真正感兴趣的是长字符串,那些有超过20或30或甚至超过80个字符的字符串,你可能真的不想知道是否有两个字符串对有3个共同字符,而其他50个是X,其余47个不匹配。

如果我是你,我会尝试 - 仍然不知道这是否适合您的申请 - 是:

1)从每个字符串中提取出有意义的最大子字符串。我想你想在开始和结束时完全忽略'X',如果一些“可读”的部分被大量的'X'破坏,那么单独处理可读部分而不是使用更长的字符串很多这个“哪个子串是相关的?”取决于你真正不知道的数据和应用程序。

2)列出这些最长的子串,以及每个子串的出现次数。按字符串长度排序此列表。您可以(但实际上不必)将每个原始字符串的索引与子字符串一起存储。你会得到像(例子)

这样的东西
AGCGCTXATCG 1
GAGXTGACCTG 2
.....
CGCXTATC    1
......

3)现在,从列表的顶部到底部:

a)将“当前字符串”设置为列表中最顶层的字符串。

b)如果当前字符串旁边的出现次数是> 1,你找到了一个匹配。如果您没有记住索引,请在原始字符串中搜索子字符串,并标记匹配。

c)将当前字符串与相同长度的所有字符串进行比较,以找到某些字符为X的匹配项。

d)从当前字符串中删除第一个字符。如果结果字符串已经在您的表中,请将其出现的计数器增加1,否则将其输入表中。

e)重复3b,使用从当前字符串中删除的最后一个字符而不是第一个字符。

f)从列表中删除当前字符串。

g)从3a)重复,直到你的计算时间用完为止,或者你剩下的字符串变得太短而不感兴趣。

如果这是一个更好的算法,很大程度上取决于你的数据和你真正感兴趣的比较。如果你的数据非常随机/你的匹配很少,它可能需要比你原来的想法更长的时间。但它可能允许您首先找到有趣的部分并跳过不太有趣的部分。

答案 1 :(得分:0)

我没有看到很多方法来改善你需要将每个字符串相互比较的事实,包括移动它们,这本身就是超长的,计算集群似乎是最好的方法。

我唯一看到如何改进的是字符串比较:用二进制模式替换A,C,T,G和X:

  • A = 0x01
  • C = 0x02
  • T = 0x04
  • G = 0x08
  • X = 0x0F
这样你可以在4位上存储一个项目,即每个字节两个(虽然这可能不是一个好主意,但仍然可以选择调查),然后用AND操作快速比较它们,这样你就可以“必须计算你有多少个连续的非零值。这只是一种处理通配符的方法,对不起,我没有更好的想法来降低整体比较的复杂性。