在Python中解决序列比对问题

2020-10-26 08:18:59

博客Jto联系如何使用Needleman-Wunsch算法和动态规划创建更有效的解决方案。

作为输出,您的目标是产生一个比对,将序列的元素配对。例如。

虽然对齐可以有间隙,但它不能更改序列元素的相对顺序。例如,不能将";CT";更改为";TC";。

具体地说,您的目标是获得最高分数。以下是如何计算分数:

因此,您的目标是获取两个序列,并找到得分最高的序列。

对于输入,我将序列表示为字符串或列表。我可以将序列";cat";表示为。

对于输出,我将对齐表示为索引元组列表(如果有差距,则为无)。例如,此对齐:

当我处理问题时,我喜欢从暴力解决方案开始。暴力解决方案往往更容易实现,而且通常情况下,对于将要遇到的实际输入来说,暴力解决方案是足够好的。

我首先创建一个函数,该函数接受两个索引范围并迭代所有可能的对齐:

从集合导入dequedef all_alignments(x,y):";";";";返回两个序列的所有比对的迭代值。X,y--序列。";";";def F(x,y):";";";递归构建对齐的辅助函数。X,y-原始x和y.";";";";if len(X)==0和len(Y)==0的序列索引:如果len(X)>;0和len(Y)>;0:Scenarios.append((x[0],x[1:],y[0],y[1:])),则产生deque()Scenario=[]if len(X)>;0和len(Y)>;0:Scenarios.append((x[0],x[1:],y[0],y[1:]))。0:Scenarios.append((x[0],x[1:],None,y))If len(Y)>;0:Scenarios.append((None,x,y[0],y[1:]))#备注:";xh";和";x-head";和";x-ail";,#其中";head";和#";尾部";是序列的其余部分。#";yh";和";yt";也是如此。对于方案中的xh、xt、yh、yt:对于F(xt,yt)中的对齐:alignment.appendleft((xh,yh))屈服对齐=F(range(len(X)),range(len(Y)返回映射(列表,对齐)。

[[(0,0),(1,1),(2,None)],[(0,0),(1,None),(2,1)],[(0,0),(1,None),(2,None),(None,1)],[(0,0),(1,None),(None,1),(2,None)],[(0,0),(None,1),(1,None),(1,None),(2,None)],[(0,None),(1,0),(2,1)],[(0,None),(1,0),(2,None),(None,1)],[(0,None),(1,0),(None,1),(2,None)],[(0,None),(1,None),(2,0),(None,1)],[(0,None),(1,None)],(2,None),(None,0),(None,1)],[(0,None),(1,None),(None,0),(2,1)],[(0,None),(1,None),(None,0),(2,None),(None,1)],[(0,None),(1,None),(None,0),(None,1),(2,None)],[(0,None),(None,0),(1,1),(2,None)],[(0,None),(None,0),(1,None),(2,1)],[(0,None),(None,0),(1,None),(2,None),(None,1)],[(0,None),(None,0),(1,None),(None,1),(2,None)],[(0,None),(None,0),(None,1),(1,None),(2,None)],[(None,0),(0,1),(1,None),(2,None)],[(None,0),(0,None),(1,1),(2,None)],[(None,0),(0,None),(1,None),(2,1)],[(None,0),(0,None),(1,None),(2,None),(None,1)],[(None,0),(0,None),(1,None),(1,None),(2,None)],[(None,0),(0,None),(None,1),(1,None),(2,None)],[(None,0),(None,1),(0,None),(1,无),(2,无)]]。

Def PRINT_ALIGNATION(x,y,Alignment):print(";";.join(";-";如果i不是其他x[i]for i,_in alignment))print(";";.join(";-";如果j不是其他y[j]for_,j对齐))x=";cat";y=";CT";对于ALL_ALIGNMENTS(x,y)中的对齐方式:PRINT_ALIGNATION(x,y,Alignment)print()。

接下来,我创建一个函数,该函数采用两个序列和一个比对来产生分数:

Def ALIGNATION_SCORE(x,y,Alignment):";";";给对齐打分。X,y--序列。对齐--x和y的对齐。";";";Score_Gap=-1 Score_Same=+1 Score_Different=-1 Score=0 for i,j in Alignment:if(i为None)或(j为None):Score+=Score_Gap Elif x[i]==y[j]:Score+=Score_Same Elif x[i]!=y[j]:Score+=Score_Different返回Score。

使用这两个函数--ALL_ALLIGNS和ALIGN_SCORE--强力解决方案将搜索所有的比对,以找到得分最高的一个:

从functools导入partaldef align_bf(x,y):";";";";比对两个序列,使用暴力将比对分数最大化。X,y--序列。";";";返回max(ALL_ALIGNMENTS(x,y),KEY=PARTIAL(ALLING_SCORE,x,y),)

这个解决方案的时间复杂度是多少?对于n和m元素的两个序列:

可能的路线数目由德尔诺伊数字给出。路线数D由递归关系给出。

D(n,m)=D(n-1,m)+D(n,m-1)+D(n-1,m-1)。

从functools导入lru_cache@lru_cache(maxSize=None)def D(n,m):如果n==0或m==0:返回1否则:返回D(n-1,m)+D(n,m-1)+D(n-1,m-1)。

D(100,100)越来越接近爱丁顿数,10e+80--可见宇宙中氢原子的估计数量。

计算比对分数所花费的时间在两个序列的大小上都是线性的:O(n+m)。

强力解决方案很简单,但规模不大。在实践中,序列比对用于分析生物数据的序列(例如核酸序列)。考虑到这些序列的大小可以是数百或数千个元素的长度,因此暴力解决方案不可能对这种大小的数据起作用。

1970年,Saul B.Needleman和Christian D.Wunsch创建了一种更快的算法来解决这个问题:Needleman-Wunsch算法。(参见适用于在两个蛋白质的氨基酸序列中搜索相似性的一般方法,https://doi.org/10.1016/0022-2836(70)90057-4.)The算法使用动态规划来解决O(m,n)时间内的序列比对问题。

这里是Needleman-Wunsch算法的Python实现,基于网格并行Needleman-Wunsch算法的第3节:

从itertools导入产品从集合导入dequedef Needleman_Wunsch(x,y):";";";对两个序列运行Needleman-Wunsch算法。X,y--序列。基于第3节伪码的代码:Naveed,Tahir;Siddiqui,Imitaz Saeed;Ahmed,Shaftab。网格的并行Needleman-Wunsch算法。Https://upload.wikimedia.org/wikipedia/en/c/c4/ParallelNeedlemanAlgorithm.pdf";";";N,M=len(X),len(Y)s=lambda a,b:int(a==b)DIAG=-1,-1 LEFT=-1,0 UP=0,-1#为范围(N)中的i创建表格F和PTR F={}PTR={}F[-1,-1]=0:对于范围(M)中的j,F[i,-1]=-I:F[-1,j]=-j Option_PTR=DIAG,LEFT,UP FOR I,J in product(Range(N))中的F[i,-1]=-I:F[-1,j]=-j Option_PTR=DIAG,Left,Up for i,j in product(Range(N)),Range(M)):Option_F=(F[i-1,j-1]+s(x[i],y[j]),F[i-1,j]-1,F[i,j-1]-1,)F[i,j],Ptr[i,j]=max(zip(Option_F,Option_Ptr))#从(N-1,M-1)倒到(0,0)#以找到最佳对齐。Align=deque()i,j=N-1,M-1 When i>;=0,j>;=0:Direction=PTR[i,j]if Direction==DIAG:Element=i,j Elif Direction==Left:Element=i,j alignment.appendLeft(Element)di,Dj=Direction i,j=i+di,j+Dj While i>;=0:Alignment.appendLeft((i,None))i-=1 When j>;=0:alignment.appendLeft((None,j))j-=1个返回列表(对齐)。

Def align_fast(x,y):";";";";使用Needleman-Wunsch算法对两个序列进行比对,使比对得分最大化。X,y--序列。";";";返回Needleman_Wunsch(x,y)ALIGN_FAST(";CAT";,";CT";)。

这个解决方案的时间复杂度是多少?对于n和m元素的两个序列:

在本周的帖子中,您学习了如何解决序列比对问题。您学习了如何创建可以生成所有可能的比对的强力解决方案。然后,您了解到暴力对于较大的序列是不可行的:两个10个元素的序列有超过800万个不同的比对!。最后,您了解了如何用Python重新实现Needleman-Wunsch算法。

如果你喜欢这周的帖子,那就和你的朋友们分享吧,敬请关注下周的帖子。回头见!。

(如果您在此帖子上发现任何错误或打字错误,请通过我的联系页面与我联系。

。)