ファイルのサブセットをランダムにサンプリングする方法


38

ファイルのサブセットをサンプリングするために使用できるLinuxコマンドはありますか?たとえば、ファイルには100万行が含まれており、そのファイルから1,000行のみをランダムにサンプリングしたいとします。

ランダムの場合、すべての行が同じ確率で選択され、選択された行はどれも繰り返されないことを意味します。

headそして、tailではなく、ランダムにファイルのサブセットを選ぶことができます。私はいつでもそうするためにPythonスクリプトを書くことができることを知っていますが、この使用法のためのコマンドがあるのではないかと思っています。


ランダムな順序の行、またはそのファイルの1000の連続した行のランダムなブロック?
frostschutz 14年

すべての行は同じ確率で選択されます。行の連続したブロックが一緒に選択される可能性はわずかですが、連続している必要はありません。私はそれを明確にするために質問を更新しました。ありがとう。
clwen

私のgithub.com/barrycarter/bcapps/tree/master/bc-fastrand.plは、ファイル内のランダムな場所をシークし、最も近い改行を見つけることにより、ほぼこれを行います。
バリーカーター

回答:


65

shufコマンド(coreutilsのの一部)がこれを行うことができます:

shuf -n 1000 file

そして、少なくとも現時点では、非古代バージョン(2013年のコミットで追加)では、必要に応じてリザーバーサンプリングを使用します。つまり、メモリ不足にならず、高速アルゴリズムを使用します。


ドキュメントによると、入力としてソートされたファイルが必要です:gnu.org/software/coreutils/manual/…– mkc 14
1

@Ketanは、そのようには思えない
frostschutz

2
@Ketanマニュアルの間違ったセクションにあると思います。マニュアルの例でもソートされていないことに注意してください。また、それsortは同じセクションにあり、ソートされた入力を必要としないことは明らかです。
デロバート14年

2
shufversion 6.0 (2006-08-15)でcoreutilsに導入されましたが、信じられないかもしれませんが、かなり一般的なシステム(特にCentOS 6.5)にはそのバージョンがありません:-|
offby1 14年

2
@petrelharp shuf -nは、少なくとも入力が8Kを超える場合にリザーバーサンプリングを実行します。これは、ベンチマークが優れていると判断したサイズです。ソースコードを参照してください(例:github.com/coreutils/coreutils/blob/master/src/shuf.c#L46)。この非常に遅い回答で申し訳ありません。どうやらそれは6年前の新しいものです。
デロバート

16

非常に大きなファイルがある場合(サンプルをとる一般的な理由)、次のことがわかります。

  1. shuf メモリを使い果たします
  2. $RANDOMファイルが32767行を超える場合、使用は正しく機能しません。

「正確に」n個のサンプリングされた行必要ない場合は、次のような比率をサンプリングできます

cat input.txt | awk 'BEGIN {srand()} !/^$/ { if (rand() <= .01) print $0}' > sample.txt

この用途定数メモリ、サンプルファイルの1%(あなたはファイルの行数を知っていればあなたがラインの限られた数に近いをサンプリングし、この要因を調整することができます)、および任意のサイズを持つ作品ファイルのが、それはしません正確な行数を返しますが、統計的な比率です。

注:コードはhttps://stackoverflow.com/questions/692312/randomly-pick-lines-from-a-file-without-slurping-it-with-unixから取得されます


ユーザーが空白以外の行の 1%を必要とする場合、これは非常に良い答えです。しかし、ユーザーが正確な行数(たとえば、1000000行のファイルのうち1000行)が必要な場合、これは失敗します。あなたがそれから得た答えが言うように、それは統計的推定のみをもたらします。そして、あなたはそれが空白行を無視していることを見るのに十分な答えを十分に理解していますか?これは実際には良い考えかもしれませんが、文書化されていない機能は一般的には良い考えではありません。
G-Manが「Reinstate Monica」と言う

1
PS   を使用した単純化アプローチ$RANDOMは、32767行を超えるファイルに対しては正しく機能しません。「使用$RANDOMしてもファイル全体に届かない」という文は少し広範です。
G-Manが「Reinstate Monica」と言う

@ G-Man質問は、例として100万行から1万行を取得することについて話しているようです。(ファイルのサイズとハードウェアの制限のため)私の周りの答えはどれもうまくいきませんでしたし、私はこれを合理的な妥協案として提案します。100万行のうち1万行を取得することはできませんが、ほとんどの実用的な目的には十分近いかもしれません。あなたのアドバイスに従って、もう少し明確にしました。ありがとう。
Txangel

これが最良の答えです。これは要件である場合に備えて、元のファイルの時系列順を尊重しながら行がランダムに選択されます。さらに、awkよりもリソースに優しいshuf
ポリメラーゼ

正確な数が必要な場合は、いつでもできます...必要以上の%でこれを実行します。結果を数えます。count modの差に一致する行を削除します。
ブルーノブロノスキー

6

@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番目のサンプルメソッドをチェーンします。


5

shuf -n大きなファイルのトリックがメモリ不足になり、固定サイズのサンプルが必要で、外部ユーティリティをインストールできる場合は、サンプルを試してください:

$ sample -N 1000 < FILE_WITH_MILLIONS_OF_LINES 

注意点は、サンプル(この例では1000行)がメモリに収まる必要があるということです。

免責事項:私は推奨ソフトウェアの著者です。


1
それをインストールし、自分の持っている人のために/usr/local/bin前に/usr/bin/自分のパスに、MacOSの内蔵と呼ばれるコールスタックサンプラーが付属していることを警戒するsample中で、完全に異なる何かを、/usr/bin/
デニスドバーナーディ

2

あなたが尋ねることを行うことができる単一のコマンドを認識していませんが、ここで私がまとめたループは仕事をすることができます:

for i in `seq 1000`; do sed -n `echo $RANDOM % 1000000 | bc`p alargefile.txt; done > sample.txt

sed1000のパスのそれぞれでランダムな行を選択します。おそらく、より効率的なソリューションがあります。


このアプローチで同じ行を複数回取得することは可能ですか?
clwen

1
はい、同じ行番号を複数回取得することはかなり可能です。さらに、$RANDOM0から32767までの範囲があります。そのため、行番号が十分に広がることはありません。
mkc 14年

仕事しません-ランダムに一度と呼ばれる
ボフダン

2

次のコードをファイルに保存し(例:randextract.sh)、次のように実行できます。

randextract.sh file.txt

----ファイルの開始----

#!/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

----ファイルの終了----


3
ここでRANDを使用して何をしようとしているの$RANDOM$RANDOMかわかりませんが、「0〜3276732767」の範囲全体で乱数を生成しません(たとえば、1000099999ではなく1000100000を生成します)。
ジル 'SO-悪であるのをやめる' 14年

OPは次のよ​​うに述べています。「すべてのラインが同じ確率で選択されます。…連続する行のブロックが一緒に選択される可能性はわずかです。」この答えは不可解であると思いますが、ランダムな開始点から連続する行の10行のブロックを抽出しているようです。それはOPが求めているものではありません。
G-Manによる「Reinstate Monica」

2

ファイルの行数がわかっている場合(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に対するもう1つの利点shufは、ファイル内の行の順序が保持されることです。

それが前提としていることを注意n されたファイルの行数。ファイルの最初の行(潜在的に多くの行がある)から印刷pする場合は、次のようにth行で停止する必要があります。 nawkn

awk -v n=1e6 -v p=1000 '
  BEGIN {srand()}
  rand() * n-- < p {p--; print}
  !n {exit}' < file

2

ヘッダー行を保持したい場合、およびサンプルがファイルのおよその割合になる可能性がある場合、これにawkを使用するのが好きです。非常に大きなファイルで動作します:

awk 'BEGIN {srand()} !/^$/ { if (rand() <= .01 || FNR==1) print > "data-sample.txt"}' data.txt

1

またはこのように:

LINES=$(wc -l < file)  
RANDLINE=$[ $RANDOM % $LINES ]  
tail -n $RANDLINE  < file|head -1  

bashのmanページから:

        RANDOMこのパラメーターが参照されるたびに、ランダムな整数
              0〜32767が生成されます。ランダムのシーケンス
              番号は、RANに値を割り当てることで初期化できます
              DOM。RANDが設定されていない場合、その特別な適切な
              後でリセットされても、関係があります。

ファイルの行数が32767行未満の場合、これはひどく失敗します。
offby1 14年

これにより、ファイルから1行が出力されます。(あなたの考えは、上記のコマンドをループで実行することだと思いますか?)ファイルに32767行以上ある場合、これらのコマンドは最初の32767行からのみ選択します。非効率の可能性は別として、ファイルの行数が32767行未満であれば、この回答に大きな問題は見られません。
G-Manが「

1

ファイルサイズが大きくない場合は、ランダムに並べ替えを使用できます。これはshufより少し時間がかかりますが、データ全体をランダム化します。したがって、要求どおりにheadを使用するには、次の手順を簡単に実行できます。

sort -R input | head -1000 > output

これにより、ファイルがランダムにソートされ、最初の1000行が表示されます。


0

受け入れられた答えで述べたように、GNU shufは単純なランダムサンプリング(shuf -n)を非常によくサポートしています。でサポートされてshufいるものを超えるサンプリング方法が必要な場合は、eBayのTSV Utilitiesのtsv-sampleを検討してください。重み付けランダムサンプリング、ベルヌーイサンプリング、個別サンプリングなど、いくつかの追加サンプリングモードをサポートしています。パフォーマンスはGNUに似ています(どちらも非常に高速です)。免責事項:私は著者です。shuf

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.