Performance 使用嵌套for循环的Perl脚本性能低下
我有一个大的FASTA文件(一个基因序列,一个完整的染色体),其中每行包含50个字符(碱基a、g、t和c)。这个文件中大约有400万行 我想重新组织文件,以便将一行中的每个字符放置在新文件中自己的行中。也就是说,将原始文件中的每50个字符行转换为50个单字符行。这将导致整个序列重写为一列。最后,我希望序列是一个单列,这样我就可以放置一个相邻的列,包含每个碱基的基因组坐标位置 我就是这样做的,使用perl并为循环创建一组Performance 使用嵌套for循环的Perl脚本性能低下,performance,perl,for-loop,nested-loops,bioinformatics,Performance,Perl,For Loop,Nested Loops,Bioinformatics,我有一个大的FASTA文件(一个基因序列,一个完整的染色体),其中每行包含50个字符(碱基a、g、t和c)。这个文件中大约有400万行 我想重新组织文件,以便将一行中的每个字符放置在新文件中自己的行中。也就是说,将原始文件中的每50个字符行转换为50个单字符行。这将导致整个序列重写为一列。最后,我希望序列是一个单列,这样我就可以放置一个相邻的列,包含每个碱基的基因组坐标位置 我就是这样做的,使用perl并为循环创建一组 unless(@ARGV) { # $0 name of the p
unless(@ARGV) {
# $0 name of the program being executed;
print "\n usage: $0 filename\n\n";
exit;
}
# use shift to pull off @ARGV value and return to $list;
my $fastafile = shift;
open(FASTA, "<$fastafile");
my @count =(<FASTA>);
close FASTA;
# print scalar @count;
for ( my $i = 0; $i < scalar @count ; $i ++ ) {
#print "$count[$i]\n\n\n\n";
my @seq = split( "", $count[ $i ] );
print " line = $i ";
for ( my $j = 0; $j < scalar @seq; $j++ ){
#my $count =
print "$seq[$j] for count = $j \n";
}
}
除非(@ARGV){
#$0正在执行的程序的名称;
打印“\n用法:$0文件名\n\n”;
出口
}
#使用shift提取@ARGV值并返回到$list;
我的$fastafile=shift;
open(FASTA,“问题在于您正在对文件进行slurp处理。在对大文件进行slurp处理时,进程将等待所有I/O完成后才开始处理。一个选项是逐行处理文件:
open my $fh, '<', $fastafile or die "Error opening file: $!";
while ( my $line = <$fh> ) {
chomp $line; # Remove the newline from the end of each line
my @seq = split //, $line;
# Loop from 0 to the last index of @seq
for my $i ( 0 .. $#seq ) {
print "$seq[$i] for count = $i\n";
}
}
打开我的$fh,”看起来您的主要限制是打印出的数据比读取的数据多几个数量级
如果每行是50个字符+换行符,则“应该”写入100/51(大约两倍)的数据
但是打印长字符串“X代表计数=29\n”意味着每个输入字符要写15-16个字符
除此之外,您还将消耗大量内存,但现在4M lines x 50 chars并不是真正的“太多”。不过,这是您不需要在这里“花费”的超过2000万的日常管理开销
也许在这个地方,编写自己的循环不如使用Perl操作符中的内置函数,比如qq
aka“
我还将变量构造移到循环之外,以节省更多的构造和垃圾收集时间
{ # Inner scope for local $" and my vars #"
local $" = "\n"; # Separator character for stringifying lists #"
my ($line, @line); # Avoid cons/gc during the loop
while ($line = <$fh>)
{
chomp $line; # Strip any newline
@line = split ('', $line);
print "@line\n"; # Stringification using $"
}
}
{#本地$“和我的变量的内部作用域#”
本地$“=”\n“#字符串化列表的分隔符#”
我的($line,@line)#在循环过程中避免cons/gc
而($line=)
{
chomp$line;#删除任何新行
@行=拆分(“”,$line);
打印“@line\n”#使用$进行字符串化
}
}
(很抱歉,Stack Exchange的语法突出显示不知道$”是一个变量名,因此语法突出显示有点奇怪。)以下内容可能会有所帮助:
use strict;
use warnings;
@ARGV or die "\n usage: $0 filename\n\n";
my $line = 0;
while (<>) {
next if /^>/;
chomp;
print 'Line = ', $line++, "\n";
my $count = 0;
print "$_ for count = ", $count++, "\n" for split '';
print "\n";
}
使用类来处理这个问题,它允许为fasta格式设置width
和block
(特定格式由处理)。如果我没记错的话,它有一些技巧来处理非常大的序列,尽管我认为这些仅限于编写部分(可耻的自我宣传,我去年实现了其中一个).像这样的东西应该很管用:
use Bio::SeqIO;
## omit the -format option and it will try to guess the format
my $in = Bio::SeqIO->new(-file => $fastafile, -format => 'Fasta');
while (my $seq = $in->next_seq()) {
my $out = Bio::SeqIO->new(-file => ">outputfilename", -format => 'Fasta');
$out->width(1); # 1 base pair per line
$out->write_seq($seq);
}
请注意,这将允许在同一个文件中包含多个fasta序列(使用一个包含6个序列和几行的fasta文件进行实验,以对其有一种感觉)
此外,这实际上写入了一个真正的fasta文件,因此您将无法更改代码来编写2列文件。但是您提到的问题,即第二列带有基索引,对我来说没有太大意义。如果您知道第一个基的偏移量,那么第二列只是$column_number+$offset+1(解释fasta头)。但是BioPerl有办法做到这一点,请不要重新发明轮子。将序列作为对象加载,并使用其方法获得子序列
my $in = Bio::SeqIO->new(-file => $fastafile);
while (my $seq = $in->next_seq()) {
## $subseq will be a string with the sequence from bp 500 to 1000
my $subseq = $seq->subseq(500, 1000);
}
我不确定这会给您带来多大的性能提升,但如果您认为您可以改进,请将其分享给BioPerl项目。您使用fasta>标题做什么?在for
循环之前,标题将被忽略。您能解释一下为什么要这样做吗?在我看来,这似乎是一个专业的标题你试图以错误的方式解决的问题,有点像你的问题是如何开门,答案是使用钥匙,但你问的是如何从安全距离炸门。嗯,也许我误解了,但输出目标实际上是“每行一个字符”还是“每行一个包含该字符的长字符串加上一个计数器”“?@carandraug,我最后想要的是一个两列文件,其中第一列是基,第二列是它的基因组坐标或基位置。序列来自UCSC基因组浏览器。你能注释(0..$#seq)吗
…这说明了什么?或者#
是一个打字错误?关于slurping,处理大约在6秒后开始,因此slurping所花费的时间与将输出打印到屏幕上所花费的时间相比并不短,这需要很长的时间。到目前为止,我等待了30分钟。终端窗口暂停(死亡之针轮旋转)每分钟左右,随着我的计算机风扇旋转。计算机变得越来越热。我明白了。我已经对范围部分进行了注释。我不能确定我的代码在这种情况下是否会运行得更快,因为我无法访问该文件。你能试试吗?$#var是Perl ese,表示“数组中的元素数@var”@BRPocock$#var
是获取@var
中最后一项的索引的语法。要获取数组中的项数,可以使用标量(@var)
(如果标量已经在标量上下文中,可以省略标量)。您能描述一下语法的含义吗?打印“$\uFor count=”.$count++,“\n”对于split//;
它看起来非常精简。split//
的表示什么意思/做什么?@ES55-不需要数组来执行您想要的处理。有问题的行首先将序列拆分成它的字符,使用for
循环对每个字符进行迭代--w
my $in = Bio::SeqIO->new(-file => $fastafile);
while (my $seq = $in->next_seq()) {
## $subseq will be a string with the sequence from bp 500 to 1000
my $subseq = $seq->subseq(500, 1000);
}