40.000行を超えるファイル(file1)があり、file2のパターンに一致する行(約6000行)を抽出します。私はこのようにgrepを使用していますが、非常に遅いです:grep -f file2 file1 > out
awk
またはsed
を使用してこれを行うより速い方法はありますか?
これが私のファイルからの抜粋です。
File1:
scitn003869.2| scign003869 CGCATGTGTGCATGTATTATCGTATCCCTTG
scitn007747.1| scign007747 CACGCAGACGCAGTGGAGCATTCCAGGTCACAA
scitn003155.1| scign003155 TAAAAATCGTTAGCACTCGCTTGGTACACTAAC
scitn018252.1| scign018252 CGTGTGTGTGCATATGTGTGCATGCGTG
scitn004671.2| scign004671 TCCTCAGGTTTTGAAAGGCAGGGTAAGTGCT
File2:
scign000003
scign000004
scign000005
scign004671
scign000013
`
grep -Fwf file2 file1 > out
をお試しください
-F
オプションはプレーンストリングマッチングを指定するため、正規表現エンジンを使用する必要がなく、より高速になるはずです。
これをawkで行う方法は次のとおりです。
awk 'NR==FNR{pats[$0]; next} $2 in pats' File2 File1
60,000行のFile1(ファイル1が8000回繰り返された)と6,000ファイル2(ユーザーが1200回繰り返した)を使用します。
$ time grep -Fwf File2 File1 > ou2
real 0m0.094s
user 0m0.031s
sys 0m0.062s
$ time awk 'NR==FNR{pats[$0]; next} $2 in pats' File2 File1 > ou1
real 0m0.094s
user 0m0.015s
sys 0m0.077s
$ diff ou1 ou2
つまり、grepと同じくらい高速です。ただし、awkソリューションでは、照合する特定のフィールドを選択できるため、File2のいずれかがFile1の他の場所に表示されても、誤って一致することはありません。また、ターゲット文字列がさまざまな長さで、たとえば「scign000003」を「scign0000031」に一致させたくない場合は、一度にフィールド全体を照合することもできます(ただし、grepの-wは同様の保護を提供します)。
完全を期すために、elsethreadに投稿された他のawkソリューションのタイミングを以下に示します。
$ time awk 'BEGIN{i=0}FNR==NR{a[i++]=$1;next}{for(j=0;j<i;j++)if(index($0,a[j]))print $0}' File2 File1 > ou3
real 3m34.110s
user 3m30.850s
sys 0m1.263s
マークが投稿したPerlスクリプトのタイミングは次のとおりです。
$ time ./go.pl > out2
real 0m0.203s
user 0m0.124s
sys 0m0.062s
あなたはこのawkで試すことができます:
awk 'BEGIN{i=0}
FNR==NR { a[i++]=$1; next }
{ for(j=0;j<i;j++)
if(index($0,a[j]))
{print $0;break}
}' file2 file1
FNR==NR
の部分は、中括弧で後に続くものが最初の入力ファイル(file2
)を処理するときにのみ適用されることを指定します。そして、あなたが探しているすべての単語を配列a[]
に保存するように言っています。中括弧の2番目のセットのビットは2番目のファイルの処理に適用されます...各行が読み込まれると、それはa[]
のすべての要素と比較され、見つかった場合はその行が出力されます。それはすべての人々です!
単に学習のために:同じ問題を解決していて、さまざまな解決策を思いついた(read $line
ループなど)。上記で見つかったgrep
ワンライナーにたどり着いたとき、私はまだ間違った出力を得ていました。次に、PATTERNファイルに2行の末尾行があることがわかりました... grep
はデータベースからすべての行を取得しました。道徳:末尾のスペース/行を確認してください。また、数百のパターンを持つ非常に大きなデータセットに対してコマンドを実行したところ、time
は数え切れませんでした。
ちょうど楽しみのために、これはPerlバージョンです:
#!/usr/bin/Perl
use strict;
use warnings;
my %patterns;
my $srch;
# Open file and get patterns to search for
open(my $fh2,"<","file2")|| die "ERROR: Could not open file2";
while (<$fh2>)
{
chop;
$patterns{$_}=1;
}
# Now read data file
open(my $fh1,"<","file1")|| die "ERROR: Could not open file1";
while (<$fh1>)
{
(undef,$srch,undef)=split;
print $_ if defined $patterns{$srch};
}
以下に、Edのファイル作成方法ごとに60,000行のfile1と6,000行のfile2を使用したタイミングをいくつか示します。
time awk 'NR==FNR{pats[$0]; next} $2 in pats' file2 file1 > out
real 0m0.202s
user 0m0.197s
sys 0m0.005s
time ./go.pl > out2
real 0m0.083s
user 0m0.079s
sys 0m0.004s