2014-01-17 122 views
-2

我的腳本設計閱讀以下形式的腳本:Perl腳本工作,但速度太慢

fixedStep chrom=chr1 start=3 step=1 
0.006 
0.010 
fixedStep chrom=chr1 start=9 step=1 
0.002 
0.004 
0.005 
fixedStep chrom=chr1 start=14 step=1 
0.010 
0.020 
0.028 
0.666 
0.777 
fixedStep chrom=chr1 start=22 step=1 
0.005 
0.009 
0.012 
0.555 

該腳本適用於這種短暫的「練習文件」。它的輸出如下:

..... 
..... 
..... 
0.006 
0.010 
..... 
..... 
..... 
..... 
0.002 
0.004 
0.005 
..... 
..... 
0.010 
0.020 
0.028 
0.666 
0.777 
..... 
..... 
..... 
0.005 
0.009 
0.012 
0.555 
..... 
..... 
..... 
..... 
..... 

所以,腳本正在做的是在單個列中列出從原始文件派生的兩件重要事情。第一種重要的是所有這些四位十進制數。第二種重要的是.....的可變數量的實例。這些代表「缺少」四位數字。從任何以fixedStep...開始的行中包含的信息計算在任何連續延伸的十進制數之前和之後發生的.....的數量。

腳本的終極目標是將練習文件展示的大版本轉換爲大版本的輸出。但正如我所說,我的解決方案很慢。任何想法改進?我確實已經寫了另一個腳本來讀取輸出,並且該腳本需要輸出我剛剛描述的特定格式。

這裏的腳本:

#!/usr/bin/perl 

use strict; use warnings; 

unless(@ARGV) { 
    exit; 
} 

my $chrpc = shift; 
open(PHAST, "<$chrpc"); 

這只是打開了該文件。接下來,我啜飲原始文件。我知道這很慢,但我從解決方案中看到的道路始於此。我懷疑這是放慢速度的最重要的事情。我承認,後來劇本變得有些複雜,而且可以「清理乾淨」,希望對錶演產生影響,而不僅僅是爲了美觀。

my @wholething =(); 
while (<PHAST>) { 
    my $line = $_; 
    chomp $line; 
    push(@wholething, $line); 
} 

接下來,我開始重新組織數據。我還補充了一些內容,比如逗號或「end」這個詞,以期在後續步驟中使用這些詞來幫助分組/合併。首先,我製作容器@chunked並將其壓入文件的第一行和逗號。

my @chunked =(); 

push (@chunked, $wholething[ 0 ], ","); 

然後循環通過@wholething,並推入@chunked文件的下一行包含的十進制數和也再次在同一行含有fixesStep,逗號「結束」,然後將下一行,隨後以逗號分隔。

for (my $i = 1; $i < scalar @wholething ; $i++) { 
     if ($wholething[ $i ]=~m/fixedStep/){ 
     chomp $wholething[ $i ]; 
     push (@chunked, $wholething[ $i ],",", "end\n", $wholething[ $i ], "," ); 
    }  

    else { 
     chomp $wholething[ $i ]; 
     push (@chunked, $wholething[ $i ], ","); 
    } 
} 

最後,我們得到的是一束「分塊」的文件,其中每個十進制數的連續運行的由相鄰含有fixedStep行括的比特,除了最後的塊,其運行的十進制數字在最前面的fixedStep行括起來。原始文件如此分塊,我可以使用側面行中的信息來決定添加多少.....來表示「缺失」信息。對於最後一個小塊,我手動輸入一個值來幫助做出這些決定。但現在,我加入@chunked成一個巨大的字符串,然後在所有「結束」事件中分割它。

my $bigstring = join ("", @chunked); 
my @chunked_array = split ("end" , $bigstring); 
#print "@chunked_array\n\n"; 

現在隨着文件的重組,我開始製作新文件。我製作一個容器@pc_array並將$last定義爲某個值。回想一下,在分塊形式中,除了最後一個塊之外,每個十進制數的運行被相鄰的fixedStep行括起來。由$last給出的值用於幫助包圍最後一個塊的結尾。在這裏,這個數字是巨大的。如果重要,這個值是染色體序列的最終位置。輸出的所有行對應於染色體中的基本位置(因此文件很大)。對於練習文件,將$last設置爲更小的數字。

my @pc_array =(); 
my $count = 1; 
my $last = 61342429; ## enter here value of final position for given chr. 

一個for loop通過每個塊週期,並找出多少.....在塊之間添加。第一次通過循環,我計算在第一個十進制數之前要添加多少個.....。最後一次通過循環我使用$last來幫助找出最終添加多少個....。其餘的,我把數組中的十進制數字,然後是適當的數字.....。我還在輸出中生成了一些健全性檢查,以確保事情正常運行。爲了生成輸出的最終形式,我將在最後刪除這些內容。我想看看數組。輸出的第一行由空格關閉。一開始就增加了額外的空間。

print @pc_array; 

我下面的刪除空間,但也主要是在輸出取出完整性檢查,以便在我需要輸出的最終形式到達。

my @pc_col =(); 

for (my $i = 2; $i < @pc_array; $i=$i+3) { 
     chomp $pc_array[ $i ]; 
     print "$pc_array[ $i ]\n"; 
     push (@pc_col, $pc_array[ $i ]."\n"); 
} 

print @pc_col; 
open(OUT, ">chr19_pc_col.txt"); 
print OUT @pc_col; 

就像我說的,腳本可以工作,但我可以使用一些指針來優化它。

+1

你的代碼是非常尷尬的閱讀分裂這樣。通常最好將盡可能少的註釋放入代碼中。請你能描述'fixedStep'線如何轉化爲輸出中的虛線?我沒有看到*「兩個」start =「的實例,後面跟着你提到的一個數字」*「。 – Borodin

+0

對不起,這是一個錯字。編輯出來。 – ES55

+0

好的,但請解釋如何確定要添加的虛線的數量。 – Borodin

回答

1

你得到了自己很糾結起來。

據我可以告訴這個程序似乎做你所需要的。我假設step屬性始終爲1,或者至少可以忽略,並且chrom字段同樣不相關。

use strict; 
use warnings; 

open my $out, '>', 'chr19_pc_col.txt' or die $!; 

my $last = 30; 

my $line = 0; 
while (<>) { 
    if (/^fixedStep.*start=(\d+)/) { 
    my $start = $1; 
    while ($line < $start) { 
     print $out ".....\n"; 
     ++$line; 
    } 
    } 
    else { 
    print $out $_; 
    ++$line; 
    } 
} 

print $out ".....\n" for $line .. $last; 

close $out or die $!; 

輸出

..... 
..... 
..... 
0.006 
0.010 
..... 
..... 
..... 
..... 
0.002 
0.004 
0.005 
..... 
..... 
0.010 
0.020 
0.028 
0.666 
0.777 
..... 
..... 
..... 
0.005 
0.009 
0.012 
0.555 
..... 
..... 
..... 
..... 
..... 
+0

這是關閉。它只是缺少最後一組'''不知道'chrom'字段是你指的還是'step'。有'$計數',我設置爲1,但然後用於幫助計數初始輸出中的行數,就像完整性檢查一樣。我最後刪除了這個,做出最終的輸出。我會嘗試你的想法。 – ES55

+0

哦...是的,我明白你的意思了。是的,step屬性總是1(我希望)。通過鉻字段,這是否指的是在輸出的最後部分做些什麼? – ES55

+0

由於'fixedStep'記錄只說明下一個數字出現的位置,因此無法知道最後要添加多少行。 – Borodin

-2

Sl does傾向於導致大文件的性能問題。

我不會做整個事情給你,但它看起來像一個類似的模式可以幫助您開始:

#buffer, holds a few lines of the input file 
my @chunk_lines =(); 

#read line-by-line until end of file 
while (!eof $fh) { 
    my $line = readline $fh; 
    if ($line =~ /^fixedStep/) {  #if this line is the start of a new chunk... 
     process_chunk(@chunk_lines); #process data 
     @chunk_lines =();   #clear buffer 
    } 

    #either way, push this line onto the buffer 
    push @chunk_lines, $line; 
} 

#process any remaining buffer 
process_chunk(@chunk_lines); 

如果你可以單獨處理每個數據塊,這是很好的。任何你將push一串值轉換成數組,然後split它下來進行處理?這是你可能能夠優化的一個點。

如果傳遞一個空@chunk_linesprocess_chunk是壞的,你能避免它簡單地說:

process_chunk(@chunk_lines) if @chunk_lines;