提高字符串重叠矩阵构建效率

Increase string overlap matrix building efficiency

本文关键字:构建 效率 重叠 字符串      更新时间:2023-10-16

我有一个由100个字符长的字符串组成的庞大列表(N=~100000),我正在努力寻找它们之间的重叠。例如,一个字符串可能是

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

您真的需要知道所有字符串对之间的匹配吗?如果是,则必须将每个字符串与其他字符串进行比较,这意味着需要n^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) 从当前字符串中删除第一个字符。如果生成的字符串已经在表中,则将其出现次数计数器增加一,否则将其输入表中。

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

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

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

如果这是一个更好的算法,这在很大程度上取决于你的数据以及你真正感兴趣的比较。如果你的数据非常随机/匹配的次数很少,这可能需要比你最初的想法更长的时间。但它可能会让你先找到有趣的部分,然后跳过不太有趣的部分。

我看不出有多少方法可以改进这样一个事实,即需要将每个字符串相互比较,包括对它们进行移位,而这本身就是超长的,计算集群似乎是最好的方法

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

  • A=0x01
  • C=0x02
  • T=0x04
  • G=0x08
  • X=0x0F
通过这种方式,您可以将一个项目存储在4位上,即每个字节两个(尽管这可能不是一个好主意,但仍然是一个可以研究的选项),然后用and运算快速比较它们,这样您就"只"需要计算有多少个连续的非零值。这只是处理通配符的一种方法,对不起,我没有更好的想法来降低整体比较的复杂性。