2つのデータファイルがあります。
File_1.in、2,000を超える行を含みます。「12 AB0001」:
10 AB0001 11 AC0002 12 AD0003 ...
gzip圧縮ファイルのリスト
*.gz
(約100万〜300万行)を抽出して解析し、行(2列目)という出力ファイルを生成する必要があります。File_1.in。##comment.. ##comment.. #CHROM POS ID REF ALT QUAL FILTER INFO FORMAT AB0001 AC0002 AD0003 21 1234567 ab11111 G A 100 PASS info1;info2 GT 0|0 0|1 0|0 21 1234568 ab22222 C A 100 PASS info1,info2 GT 1:23:2 .:.:. 0:32:2 21 1234569 ab33333 A C 100 PASS info1;info2 GT 0|2 1|0 0|0
さまざまなアプローチを試みた結果、次の結論に達しました。
{
if(FNR==NR){list[$1]=$2;next}
if(!/^#/){
for(p in list){
split($p, sp, ":");
if (sp[1] != "0|0" && sp[1] != "0" && sp[1] != "."){
printf("%s %s %s %s %s %s %s %s %s %s\n",
$1, $2, $3, $4, $5, $6, $7, $8, $9, $p) >> out"/"list[p]".tmp"
}
}
}
}
コマンドラインから実行:
awk -v out="outfolder/" -f myscript.awk file_1.in <(zcat *.gz)
ただし、ファイルを作成するのに2時間以上かかります。私のコードを改善する方法はありますか?ほとんどの時間をファイル一つ一つ消費zcat
し、追加書き込み機能が遅いようです。どう思いますか?
ベストアンサー1
このコードは、反復間で同じループで多くの処理を実行します。 awksには、ループから削除するための複雑なループ最適化はありません。
for(p in list){
split($p, sp, ":");
if (sp[1] != "0|0" && sp[1] != "0" && sp[1] != "."){
連想配列を埋めるために最初のファイルを読み取った後、連想配列は変更されませんが、list
この条件をテストするためにインデックス値を繰り返し分割します。代わりに、配列を繰り返して一致しない項目を削除できます。または...処理中に最初からこれらの項目を配列に挿入しないでくださいfile_1.in
。その後、分割とテストを削除できます。ループ内の各項目は無条件にアクセスされますlist
。
printf("%s %s %s %s %s %s %s %s %s %s\n",
$1, $2, $3, $4, $5, $6, $7, $8, $9, $p) >> out"/"list[p]".tmp"
%s
ここに印刷された素材は、最後のフィールドを除いてループの各反復に対して同じです$p
。sprintf
ループの外側を使用して9つのフィールドを文字列にフォーマットしたstr
後、次のことができますprintf("%s %s", str, $p) >> out "/" list[p] ".tmp"
。
明確ではない点:
$p
仮定の式はインデックスフィールドに適合する整数です。したがって、全体のロジックは偽のように見えます。つまり、役割を分割し、その分割の一部のフィールドをテストします。正の整数が予想される場合は、コロンを含めないでください。おそらくここで2番目の列をテストする予定ですか?printf
p
split
p
:
p
list[p]
それに加えて、プログラムの速度が大幅に遅くなる可能性があります。多数の出力ファイルに少量のデータが追加される、数千のオープンファイル記述子を維持します。圧縮ファイルの数百万行:各行に対して、ループは2,000を超える項目を含む連想配列を繰り返し、出力をさまざまなファイルに生成します。したがって、数百万の圧縮行は数十億の非圧縮行になります。
データをこの表現に拡張する目的が何であるか、自分に尋ねたいと思うかもしれません。後続処理の場合は、スペースを節約する表現を使用できます。コードawk
は、ある種のデータベースが暗黙的に処理できる一連の関連を事前計算するようです。