内容のファイルがあります
abc
def
high
lmn
...
...
ファイルには 200 万行を超える行があります。ファイルから行をランダムにサンプリングし、50K 行を出力したいと考えています。この問題にアプローチする方法について何か考えはありますか? 私は、Perl とその機能の方針に沿って考えていましたrand
(または、便利なシェル コマンドが適切でしょう)。
関連する (おそらく重複する) 質問:
内容のファイルがあります
abc
def
high
lmn
...
...
ファイルには 200 万行を超える行があります。ファイルから行をランダムにサンプリングし、50K 行を出力したいと考えています。この問題にアプローチする方法について何か考えはありますか? 私は、Perl とその機能の方針に沿って考えていましたrand
(または、便利なシェル コマンドが適切でしょう)。
関連する (おそらく重複する) 質問:
基本的にすべての行の約2.5%を出力したい場合、これは次のようになります。
print if 0.025 > rand while <$input>;
シェルウェイ:
sort -R file | head -n 50000
perlfaq5から:「ファイルからランダムな行を選択するにはどうすればよいですか?」
ファイルをデータベースにロードしたり、ファイル内の行に事前にインデックスを付けたりする以外に、実行できることがいくつかあります。
CamelBookのリザーバーサンプリングアルゴリズムは次のとおりです。
srand;
rand($.) < 1 && ($line = $_) while <>;
これは、ファイル全体を読み込むよりもスペースに大きな利点があります。この方法の証明は、DonaldE.KnuthによるTheArtof Computer Programming 、Volume 2、Section3.4.2にあります。
そのアルゴリズムの関数を提供するFile::Randomモジュールを使用できます。
use File::Random qw/random_line/;
my $line = random_line($filename);
もう1つの方法は、ファイル全体を配列として扱うTie::Fileモジュールを使用することです。ランダムな配列要素にアクセスするだけです。
正確な数の行を抽出する必要がある場合:
use strict;
use warnings;
# Number of lines to pick and file to pick from
# Error checking omitted!
my ($pick, $file) = @ARGV;
open(my $fh, '<', $file)
or die "Can't read file '$file' [$!]\n";
# count lines in file
my ($lines, $buffer);
while (sysread $fh, $buffer, 4096) {
$lines += ($buffer =~ tr/\n//);
}
# limit number of lines to pick to number of lines in file
$pick = $lines if $pick > $lines;
# build list of N lines to pick, use a hash to prevent picking the
# same line multiple times
my %picked;
for (1 .. $pick) {
my $n = int(rand($lines)) + 1;
redo if $picked{$n}++
}
# loop over file extracting selected lines
seek($fh, 0, 0);
while (<$fh>) {
print if $picked{$.};
}
close $fh;
パールの方法:
CPAN を使用します。必要なことを正確に行うモジュールFile::RandomLineがあります。