设为首页 收藏本站
查看: 2858|回复: 0

[经验分享] Needleman-Wunsch 算法perl实现版

[复制链接]

尚未签到

发表于 2015-12-26 09:06:38 | 显示全部楼层 |阅读模式
  第一次写博客心情还是有点小激动的。其实写博客的初衷是为了将自己所学到的知识分享给大家,在这个过程中,也能让自己对整个过程有着更清晰的认识,锻炼自己的分析和归纳能力。
  废话不多说,今天第一弹为大家献上生物信息学中最基本也是非常关键的序列比对算法。序列比对分为两序列比对和多序列比对,在两序列比对中主要存在两类算法:穷举式精确算法和基于启发式的近似算法。今天给大家介绍的就是穷举式精确算法中的Needleman-Wunsch算法,此算法是全局比对算法,其要点在于要想得到两个序列的最佳比对,首先求得其子序列的最佳比对,子序列的最佳比对又接着从子序列的子序列的最佳比对中取得,这样一层一层递推下去,最后得到两序列比对的最佳形式。
  假定采用“固定空位罚分模型”,打分模板采用S(a,a)=1,S(a,b)=-1,S(-,a)=S(a,-)=-2;两条序列分别为s和t,对应长度为m和n。算法流程如下:
  1、构建一个(m+1)×(n+1)的矩阵H,其中每个值Hi,j的含义为序列s中前i个子序列和t中前j个子序列的最佳比对得分。
  2、Hi,j的最佳比对得分存在三种状况:


  • si和tj刚好比对或替换----子序列为Hi-1,j-1;
  • si和空位比对------------子序列为Hi-1,j;
  • 空位和tj比对------------子序列为Hi,j-1;
  以这种方式逐层往下递推,同时每个Hi,j都需记录下其取得最佳比对是从何种子序列而来。
  3、从Hm,n中寻找一条到达H0,0的路径,此路径即为两序列比对的最佳形式
  若想取得所有最佳比对的序列形式,则问题转化为在两个节点之间寻找所有路径,即有向图的遍历问题。对于两序列比对,这样做或许意义不大,但对于自己而言刚好是可以锻炼的一个机会,可大学时学的数据结构早已还给老师,于是在网上复习回顾了一下有向图的遍历算法,决定采用深度优先遍历,取得所有最佳比对的路径。
  下面是用perl实现的算法:



  1 use strict;
  2 use warnings;
  3
  4 my @F=([],[]);            ##存放两条比对序列的二维数组;
  5 my @H;                    ##存放比对序列得分的二维数组;
  6 my @S;                    ##存放二维数组H中每个值状态的三维数组;
  7 my @S_number;             ##存放H[j]所有可选状态的数目,与三维数组S相对应;
  8 my @S_number_copy;        ##存放S_number的一个copy,用于判断回溯节点的原始可选择路径数目;
  9 my @route;                ##存放从H[m][n]到H[0][0]的路径的边;
10 my @route_node;           ##存放从H[m][n]到H[0][0]的路径的节点;
11 my @route_node_number;    ##存放从H[m][n]到H[0][0]的路径的节点的剩余状态数;
12 my $route_number=0;       ##所有最佳比对的数目;
13 my $m;my $n;              ##两条序列的长度;
14
15 my @query;                ##最终输出序列的形式;
16 my @target;               ##最终输出序列的形式;
17 my $t_q=0;               
18 my $t_t=0;
19
20 ##将两条待比对序列存进二维数组F;
21 open QUERY,'<','E:\perl\Algorithm\query.txt' or die "$!";
22 while(<QUERY>){
23     chomp;
24     s/\s+//g;
25     s/^\s+//g;
26     s/(\w+)/\U$1/g;
27     my @first=split //;
28     push @{$F[0]},@first;
29 }
30 close QUERY;
31 open TARGET,'<','E:\perl\Algorithm\target.txt' or die "$!";
32 while (<TARGET>){
33     chomp;
34     s/\s+//g;
35     s/^\s+//g;
36     s/(\w+)/\U$1/g;
37     my @second=split //;
38     push @{$F[1]},@second;
39 }
40 close TARGET;
41
42 ##二维数组H和S_number的初始化;
43 $m=@{$F[0]};
44 $n=@{$F[1]};
45 $H[0][0]=0;
46 $S_number[0][0]=0;
47 @{$H[0]}=map {$_*(-2)} my @n=(0..$n);
48 for(my $i=1;$i<=$n;$i++){
49     $S_number[0][$i]=1;
50 }
51 for(my $i=1;$i<=$m;$i++){
52     $H[$i][0]=(-2)*$i;
53     $S_number[$i][0]=1;
54 }
55 ##三维数组S的初始化
56 @{$S[0][0]}=();
57 for(my $i=1;$i<=$n;$i++){
58     @{$S[0][$i]}='left';
59 }
60 for (my $i=1;$i<=$m;$i++){
61     @{$S[$i][0]}='up';
62 }
63 ##计算H[j]子程序;
64 sub max{
65     my %status;     
66     my $a=$_[0];my $b=$_[1];
67     if($F[0][$a-1] eq $F[1][$b-1]){
68         $status{left_up}=$H[$a-1][$b-1]+1;
69     }
70     else{
71         $status{left_up}=$H[$a-1][$b-1]-1;
72     }
73     $status{up}=$H[$a-1][$b]-2;
74     $status{left}=$H[$a][$b-1]-2;
75     my $max=$status{left_up};
76     my @score_status;
77 ##利用高水线,取得三种状态下的最大值;
78     foreach (keys %status){
79         if($status{$_} > $max){
80             $max=$status{$_};
81         }
82     }
83     push @score_status,$max;
84     foreach (keys %status){
85         if($status{$_} == $max){
86             push @score_status,$_;
87         }
88     }
89     @score_status;
90 }
91 ##计算每个H[j]的值并将每个值对应的状态存入三维数组S中;
92 for(my $i=1;$i<=$m;$i++){
93     for(my $j=1;$j<=$n;$j++){
94         my @temp=&max($i,$j);
95         $H[$i][$j]=shift @temp;
96         my $status_number=@temp;
97         $S_number[$i][$j]=$status_number;
98         @{$S[$i][$j]}=@temp;
99     }
100 }
101 ##将二维数组复制一份copy为S_number_copy;
102 for(my $i=0;$i<=$m;$i++){
103     for(my $j=0;$j<=$n;$j++){
104         $S_number_copy[$i][$j]=$S_number[$i][$j];
105     }
106 }
107 ##输出每个H[j]的值以及对应的状态;
108 for (my $i=0;$i<=$m;$i++){
109     print "@{$H[$i]}\n";
110 }
111 for(my $i=0;$i<=$m;$i++){
112     for(my $j=0;$j<=$n;$j++){
113         print "{"."@{$S[$i][$j]}"."}";
114     }
115     print "\n";
116 }
117 ##依据三维数组S,寻找路径上的下一个位置
118 sub next{
119     my $status=$_[0];
120     my @position;
121         if ($status eq 'left'){
122         my $i=$_[1];my $j=$_[2]-1;
123         @position=($i,$j);
124     }
125         if ($status eq 'up'){
126         my $i=$_[1]-1;my $j=$_[2];
127         @position=($i,$j);
128     }
129         if ($status eq 'left_up'){
130         my $i=$_[1]-1;my $j=$_[2]-1;
131         @position=($i,$j);        
132     }
133     return @position;
134 }
135
136 ##深度优先遍历路径,每个路径存放入二维数组route中;
137 ROUTE:{
138     while ($m>0 || $n>0){
139      my $status;
140      my $status_number;
141      my @next_position;
142      $status=$S[$m][$n][0];
143      my $temp=shift @{$S[$m][$n]};
144      push @{$S[$m][$n]},$temp;
145      $S_number[$m][$n]=$S_number[$m][$n]-1;
146      $status_number=$S_number[$m][$n];
147      push @{$route[$route_number]},$status;
148      push @{$route_node[$route_number]},($m,$n);
149      push @{$route_node_number[$route_number]},$status_number;
150      @next_position=&next($status,$m,$n);
151      $m=$next_position[0];$n=$next_position[1];
152     }
153     $route_number++;
154     @{$route[$route_number-1]}=reverse @{$route[$route_number-1]};
155     @{$route_node_number[$route_number-1]}=reverse @{$route_node_number[$route_number-1]};
156     @{$route_node[$route_number-1]}=reverse @{$route_node[$route_number-1]};
157     my $count=0;
158     foreach(@{$route_node_number[$route_number-1]}){
159          $m=$route_node[$route_number-1][$count*2+1];$n=$route_node[$route_number-1][$count*2];     
160          my $number=@{$route[$route_number-1]};
161         my $last=$number-1;                                                                        
162          if ($_>0){
163         ##若回溯的节点是顶点
164             if ($count==$last){
165                 redo ROUTE;
166             }else{
167                 my @temp1=@{$route[$route_number-1]}[$count+1..$last];
168                 push @{$route[$route_number]},reverse @temp1;
169                 
170                 my @temp2=@{$route_node[$route_number-1]}[$count*2+2..$last*2+1];
171                 push @{$route_node[$route_number]},reverse @temp2;
172                 
173                 my @temp3=@{$route_node_number[$route_number-1]}[$count+1..$last];
174                 push @{$route_node_number[$route_number]},reverse @temp3;
175                 
176                 redo ROUTE;
177             }
178          }
179          ##若回溯的的节点之前已被回溯且可选择路径布置一条,重新将其可回溯状态设为原始可选择路径数目的n-1次;
180          if($_<0 && $S_number_copy[$m][$n]>1){
181                  my @temp1=@{$route[$route_number-1]}[$count+1..$last];
182                 push @{$route[$route_number]},reverse @temp1;
183                 
184                 my @temp2=@{$route_node[$route_number-1]}[$count*2+2..$last*2+1];
185                 push @{$route_node[$route_number]},reverse @temp2;
186                 
187                 my @temp3=@{$route_node_number[$route_number-1]}[$count+1..$last];
188                 push @{$route_node_number[$route_number]},reverse @temp3;
189                 
190                 $S_number[$m][$n]=$S_number_copy[$m][$n]-1;
191                 redo ROUTE;
192          }
193         $count++;
194     }
195 }
196
197 ##输出两个序列的比对
198 $route_number=@route;
199 print "The total route number is:$route_number\n";
200 for(my $i=0;$i<$route_number;$i++){
201     print "@{$route[$i]}\n";
202     foreach(@{$route[$i]}){
203         if ($_ eq 'left_up'){
204             push @query,$F[0][$t_q];
205             push @target,$F[1][$t_t];
206             $t_q++;
207             $t_t++;
208            
209     }
210         if ($_ eq 'left'){
211             push @query,"-";
212             push @target,$F[1][$t_t];
213             $t_t++;
214     }
215         if ($_ eq 'up'){
216             push @query,$F[0][$t_q];
217             push @target,"-";
218             $t_q++;
219     }
220  }
221     print "@query\n";
222     print "@target\n";
223     $t_q=0;$t_t=0;
224     @query=();@target=();
225 }
  下面是两条测试的序列:
  s=CTGAAAA;t=CAGAA;
  输出结果如下:
DSC0000.png
  但是大家千万不要用这个程序比对两条较长的序列,一是因为算法本身的空间和时间复杂度都很高,二是因为深度优先遍历的缘故,三是程序本身并没有进行优化。比对较长序列时肯定会导致电脑死机(除非是大型计算机)。如何改进这些问题有待进一步的学习.........
  好,今天就到此为止,接下来将为大家献上更多用perl实现的生物信息学算法。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-156413-1-1.html 上篇帖子: Peter’s Perl Examples 下篇帖子: perl教程(3)
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表