ファイルのサブセットをサンプリングするために使用できるLinuxコマンドはありますか?たとえば、ファイルに100万行が含まれている場合、そのファイルからランダムに1000行だけをサンプリングしたいとします。
ランダムとは、すべてのラインが同じ確率で選択されることを意味し、選択されたラインはどれも反復的ではありません。
head
およびtail
は、ファイルのサブセットを選択できますが、ランダムにはできません。私は常にpythonスクリプトを記述できることを知っていますが、この使用法のためのコマンドがあるのだろうかと思います。
shuf
コマンド(coreutilsの一部)はこれを行うことができます:
shuf -n 1000 file
そして、少なくとも今のところ非古代バージョン( commit from 201 で追加)では、必要に応じてリザーバーサンプリングを使用します。つまり、メモリ不足にならず、高速アルゴリズムを使用しています。
非常に大きなファイルがある場合(これはサンプルを取る一般的な理由です)、次のことがわかります:
shuf
はメモリを使い果たします$RANDOM
_の使用は正しく機能しませんn個のサンプリングされた行を正確に必要としない場合比率をサンプリングすることができます このような:
cat input.txt | awk 'BEGIN {srand()} !/^$/ { if (Rand() <= .01) print $0}' > sample.txt
これは定数メモリを使用し、ファイルの1%をサンプリングします(もしファイルの行数がわかっているので、この係数を調整して、限られた数の行に近い値をサンプリングできます。任意のサイズのファイルで機能しますしかし、それはできませんprecise行の数を返します比。
注:コードは次のようになります: https://stackoverflow.com/questions/692312/randomly-pick-lines-from-a-file-without-slurping-it-with- UNIX
@Txangelの確率的ソリューションに似ていますが、100倍速く近づきます。
Perl -ne 'print if (Rand() < .01)' huge_file.csv > sample.csv
高いパフォーマンスと正確なサンプルサイズが必要であり、ファイルの最後にサンプルギャップがあっても問題ない場合は、次のようなことができます(1m行のファイルから1000行をサンプリングします)。
Perl -ne 'print if (Rand() < .0012)' huge_file.csv | head -1000 > sample.csv
..またはhead
の代わりに2番目のサンプルメソッドを実際にチェーンします。
shuf -n
大きなファイルでトリックを実行するとメモリが不足し、固定サイズのサンプルが必要であり、外部ユーティリティをインストールしてから sample を試すことができます。
$ sample -N 1000 < FILE_WITH_MILLIONS_OF_LINES
注意点は、sample(この例では1000行)がメモリに収まる必要があるということです。
免責事項:私は推奨ソフトウェアの作成者です。
あなたが求めることを実行できる単一のコマンドを認識していませんが、ここに私が一緒に仕事をすることができるループがあります:
for i in `seq 1000`; do sed -n `echo $RANDOM % 1000000 | bc`p alargefile.txt; done > sample.txt
sed
は、1000回のパスごとにランダムなラインをピックアップします。おそらくより効率的なソリューションがあります。
ファイルの行数がわかっている場合(例では1e6のように)、次のことができます。
awk -v n=1e6 -v p=1000 '
BEGIN {srand()}
Rand() * n-- < p {p--; print}' < file
そうでない場合は、いつでも行うことができます
awk -v n="$(wc -l < file)" -v p=1000 '
BEGIN {srand()}
Rand() * n-- < p {p--; print}' < file
これはファイルで2つのパスを実行しますが、ファイル全体をメモリに保存することは避けます。
GNU shuf
に対するもう1つの利点は、ファイル内の行の順序が保持されることです。
n
isファイルの行数を想定していることに注意してください。ファイルのfirstp
行からn
を出力したい場合は(これにより多くの行が含まれる可能性があります)、awk
でn
番目 次のような行:
awk -v n=1e6 -v p=1000 '
BEGIN {srand()}
Rand() * n-- < p {p--; print}
!n {exit}' < file
次のコードをファイル(例:randextract.sh)に保存し、次のように実行できます。
randextract.sh file.txt
---- BEGIN FILE ----
#!/bin/sh -xv
#configuration MAX_LINES is the number of lines to extract
MAX_LINES=10
#number of lines in the file (is a limit)
NUM_LINES=`wc -l $1 | cut -d' ' -f1`
#generate a random number
#in bash the variable $RANDOM returns diferent values on each call
if [ "$RANDOM." != "$RANDOM." ]
then
#bigger number (0 to 3276732767)
Rand=$RANDOM$RANDOM
else
Rand=`date +'%s'`
fi
#The start line
START_LINE=`expr $Rand % '(' $NUM_LINES - $MAX_LINES ')'`
tail -n +$START_LINE $1 | head -n $MAX_LINES
----ファイル終了----
ヘッダー行を保持したい場合、およびサンプルがファイルのおおよそのパーセンテージになる可能性がある場合は、これにawkを使用するのが好きです。非常に大きなファイルで機能します:
awk 'BEGIN {srand()} !/^$/ { if (Rand() <= .01 || FNR==1) print > "data-sample.txt"}' data.txt
またはこのように:
LINES=$(wc -l < file)
RANDLINE=$[ $RANDOM % $LINES ]
tail -n $RANDLINE < file|head -1
Bashのmanページから:
RANDOMこのパラメータが参照されるたびに、0〜32767のランダムな整数 が生成されます。ランダムな 番号のシーケンスは、RAN- DOMに値を割り当てることで初期化できます。 RANDOMが設定されていない場合、その後リセットされても、特別な固有の 関係は失われます。
隣接する行の単一のランダムなブロックを取得するには、shuf
を使用して1つのランダムな行を取得し、次にgrep
を使用してランダムに選択された行の後の行のブロックを取得します。
$ shuf -n 1 file | grep -f - -A 10 file
これにより、ファイルに2回アクセスします。 -fパラメータは、ファイルから検索パターンを取得するようにgrepに指示します。この場合、ファイルからランダムに選択された単一の行であるstdin(fパラメータの値としてダッシュを使用)です。
簡単な関数:
function random-block {
shuf -n 1 $1 | grep -f - -A $(($2>0?$2-1:0)) $1
}
使用例:
$ random-block /var/log/syslog 10
実際、ランダムな選択が遠すぎてブロックを選択するときに十分な行が残っていない場合、これは要求された行数の出力を保証しません。
拡張機能は次のようになります。
function random-block {
head -n $(($(wc -l | cut -f1 -d ' ')-$2+1)) $1 | shuf -n 1 | grep -f - -A $(($2>0?$2-1:0)) $1
}
これにより、最後のn行を除くファイル内のすべての行が取得され、その行のリストがシャッフルされます。これにより、grepは常に要求された行数を選択できるようになります。
ファイルサイズが大きくない場合は、ランダムに並べ替えを使用できます。これはshufよりも少し時間がかかりますが、データ全体をランダム化します。したがって、次のようにして、要求どおりにヘッドを使用することが簡単にできます。
sort -R input | head -1000 > output
これにより、ファイルがランダムにソートされ、最初の1000行が表示されます。
受け入れられた回答で述べたように、GNU shuf
は単純なランダムサンプリングをサポートします(shuf -n
)結構です。 shuf
でサポートされている以外のサンプリング方法が必要な場合は、 evayのTSVユーティリティ から tsv-sample を検討してください。加重ランダムサンプリング、ベルヌーイサンプリング、個別サンプリングなど、いくつかの追加のサンプリングモードをサポートしています。パフォーマンスはGNU shuf
に似ています(どちらも非常に高速です)。免責事項:私は著者です。