Algorithm 如何修改Smith和Waterman perl脚本以加快速度?
我找到了这个perl脚本,但是我有太多的序列要分析。我想知道是否有可能优化它?我在上面发布了NYTProf,看到“计算比赛分数”、“计算差距分数”和“选择最佳分数”花费了很多时间。我必须修改数据结构吗?谢谢你的帮助 包含以下引用的perl脚本:Algorithm 如何修改Smith和Waterman perl脚本以加快速度?,algorithm,perl,alignment,bioinformatics,Algorithm,Perl,Alignment,Bioinformatics,我找到了这个perl脚本,但是我有太多的序列要分析。我想知道是否有可能优化它?我在上面发布了NYTProf,看到“计算比赛分数”、“计算差距分数”和“选择最佳分数”花费了很多时间。我必须修改数据结构吗?谢谢你的帮助 包含以下引用的perl脚本: # Smith-Waterman Algorithm # from this website http://etutorials.org/Misc/blast/Part+II+Theory/Chapter+3.+Sequence+Alignme
# Smith-Waterman Algorithm
# from this website http://etutorials.org/Misc/blast/Part+II+Theory/Chapter+3.+Sequence+Alignment/3.2+Local+Alignment+Smith-Waterman/
# Smith-Waterman Algorithm
# usage statement
die "usage: $0 <sequence 1> <sequence 2>\n" unless @ARGV == 2;
# get sequences from command line
my ($seq1, $seq2) = @ARGV;
# scoring scheme
my $MATCH = 1; # +1 for letters that match
my $MISMATCH = -1; # -1 for letters that mismatch
my $GAP = -1; # -1 for any gap
# initialization
my @matrix;
$matrix[0][0]{score} = 0;
$matrix[0][0]{pointer} = "none";
for(my $j = 1; $j <= length($seq1); $j++) {
$matrix[0][$j]{score} = 0;
$matrix[0][$j]{pointer} = "none";
}
for (my $i = 1; $i <= length($seq2); $i++) {
$matrix[$i][0]{score} = 0;
$matrix[$i][0]{pointer} = "none";
}
# fill
my $max_i = 0;
my $max_j = 0;
my $max_score = 0;
for(my $i = 1; $i <= length($seq2); $i++) {
for(my $j = 1; $j <= length($seq1); $j++) {
my ($diagonal_score, $left_score, $up_score);
# calculate match score
my $letter1 = substr($seq1, $j-1, 1);
my $letter2 = substr($seq2, $i-1, 1);
if ($letter1 eq $letter2) {
$diagonal_score = $matrix[$i-1][$j-1]{score} + $MATCH;
}
else {
$diagonal_score = $matrix[$i-1][$j-1]{score} + $MISMATCH;
}
# calculate gap scores
$up_score = $matrix[$i-1][$j]{score} + $GAP;
$left_score = $matrix[$i][$j-1]{score} + $GAP;
if ($diagonal_score <= 0 and $up_score <= 0 and $left_score <= 0) {
$matrix[$i][$j]{score} = 0;
$matrix[$i][$j]{pointer} = "none";
next; # terminate this iteration of the loop
}
# choose best score
if ($diagonal_score >= $up_score) {
if ($diagonal_score >= $left_score) {
$matrix[$i][$j]{score} = $diagonal_score;
$matrix[$i][$j]{pointer} = "diagonal";
}
else {
$matrix[$i][$j]{score} = $left_score;
$matrix[$i][$j]{pointer} = "left";
}
} else {
if ($up_score >= $left_score) {
$matrix[$i][$j]{score} = $up_score;
$matrix[$i][$j]{pointer} = "up";
}
else {
$matrix[$i][$j]{score} = $left_score;
$matrix[$i][$j]{pointer} = "left";
}
}
# set maximum score
if ($matrix[$i][$j]{score} > $max_score) {
$max_i = $i;
$max_j = $j;
$max_score = $matrix[$i][$j]{score};
}
}
}
# trace-back
my $align1 = "";
my $align2 = "";
my $j = $max_j;
my $i = $max_i;
while (1) {
last if $matrix[$i][$j]{pointer} eq "none";
if ($matrix[$i][$j]{pointer} eq "diagonal") {
$align1 .= substr($seq1, $j-1, 1);
$align2 .= substr($seq2, $i-1, 1);
$i--; $j--;
}
elsif ($matrix[$i][$j]{pointer} eq "left") {
$align1 .= substr($seq1, $j-1, 1);
$align2 .= "-";
$j--;
}
elsif ($matrix[$i][$j]{pointer} eq "up") {
$align1 .= "-";
$align2 .= substr($seq2, $i-1, 1);
$i--;
}
}
$align1 = reverse $align1;
$align2 = reverse $align2;
print "$align1\n";
print "$align2\n";
史密斯-沃特曼算法
#从本网站http://etutorials.org/Misc/blast/Part+II+理论/第+3章+顺序+对齐/3.2+局部+对齐+史密斯-沃特曼/
#史密斯-沃特曼算法
#使用说明
除非@ARGV==2,否则为“用法:$0\n”;
#从命令行获取序列
my($seq1,$seq2)=@ARGV;
#计分制
我的$MATCH=1;#+1表示匹配的字母
我的美元错配=-1;#-1表示不匹配的字母
我的$GAP=-1;#-1.任何差距
#初始化
我的@矩阵;
$matrix[0][0]{score}=0;
$matrix[0][0]{pointer}=“无”;
对于(my$j=1;$j),您可以尝试避免反复做相同的事情
my $string = "Hello, how are you?";
my @chars = split //, $string; # Or: unpack 'a*', $string
print "Eighth char: $chars[7]\n";
my$letter2=substr($seq2,$i-1,1);
可以转到外循环,因为j
内循环从不改变
for(my $i = 1; $i <= length($seq2); $i++) {
my $letter2 = substr($seq2, $i-1, 1);
for(my $j = 1; $j <= length($seq1); $j++) {
指针
的值,使用整数代替字符串。您可以使用常量使其可读
use constant {
POINTER_NONE => 0,
POINTER_LEFT => 1,
...
};
$j-1
和$i-1
也可能带来一点好处所有这些都是微小的改进。真正的问题是你有一个二次算法。你可以尝试避免重复做同样的事情
my $string = "Hello, how are you?";
my @chars = split //, $string; # Or: unpack 'a*', $string
print "Eighth char: $chars[7]\n";
my$letter2=substr($seq2,$i-1,1);
可以转到外循环,因为j
内循环从不改变
for(my $i = 1; $i <= length($seq2); $i++) {
my $letter2 = substr($seq2, $i-1, 1);
for(my $j = 1; $j <= length($seq1); $j++) {
指针
的值,使用整数代替字符串。您可以使用常量使其可读
use constant {
POINTER_NONE => 0,
POINTER_LEFT => 1,
...
};
$j-1
和$i-1
也可能带来一点好处所有这些都是微小的改进。真正的问题是你有一个二次算法。真正的问题是你有一个二次算法。它天生就很慢。但是,该算法是解决最长公共子串问题的动态方法的变体,你做得再好不过了 也就是说,这是一个具有以下特性的实现:
- 将内存量从O(M*N)减少到O(M+N)
- 返回所有可能的解决方案(无需额外费用!!!)
- 在Perl中应该尽可能快
真正的问题是,你有一个二次算法。它本质上是缓慢的。然而,该算法是解决最长公共子串问题的动态方法的一个变种,你不能做得更好 也就是说,这是一个具有以下特性的实现:
- 将内存量从O(M*N)减少到O(M+N)
- 返回所有可能的解决方案(无需额外费用!!!)
- 在Perl中应该尽可能快
用C重写它?它已经用“C风格的Perl”编写了很多,并且它没有使用任何很难翻译成C的Perlish习语。谢谢你的建议,但不幸的是,我不是C程序员!使用现有的S-W实现,它是用C编写的?为什么你必须使用这个特定的脚本?你是对的,这是一个好主意。事实上,我有另一个perl脚本运行这个脚本d解析结果。但是我也可以调用C脚本!谢谢你的建议。用C重写它?它已经用“C风格的Perl”编写了很多,并且它没有使用任何很难翻译成C的Perlish习语。谢谢你的建议,但不幸的是,我不是C程序员!使用现有的S-W实现,它是用C编写的?为什么你必须使用这个特定的脚本?你是对的,这是一个好主意。事实上,我有另一个perl脚本运行这个脚本d解析结果。但是我也可以调用C脚本!谢谢你的建议。谢谢你的建议。关于你的第二点,我将尝试解决它。但是你对预先计算
$j-1
意味着什么呢?做我的$jm1=$j-1;
,然后使用$jm1
,而不是$j-1
。我认为这里节省的是噪音。一个更好的主意可能是对我的$i(0..length($seq2)-1)使用,
而不是对我的$i(1..length($seq2))@MrSmith42,我希望你不介意我的添加。如果你介意,请随时回复。你“真正的问题是你有一个二次算法。”,该算法是解决最长公共子串问题的动态方法的一种变体。你做得再好不过了。(也就是说,虽然是O(N*M)处理时间,但它能在这段时间内找到所有解,而不仅仅是一个。)我认为可以减少代码使用的内存,但我看不到有任何方法可以显著减少处理时间。好的,谢谢ikegami的建议。我不确定如何减少分析时间,但我会使用您的所有注释。也许我可以尝试使用称为此的脚本来解析我的文件。谢谢又是你!谢谢你的建议