Wählen Sie zufällige Zeilen aus einer Datei aus


239

In einem Bash-Skript möchte ich N zufällige Zeilen aus der Eingabedatei auswählen und in eine andere Datei ausgeben.

Wie kann das gemacht werden?


Sortieren Sie die Datei nach dem Zufallsprinzip und wählen Sie N erste Zeilen aus.
Piotr Praszmo


31
Dies ist kein Duplikat - er möchte N Zeilen gegen 1 Zeile.
OneSolitaryNoob


1
Ich bin damit nicht einverstanden, sort -Rda es viel überschüssige Arbeit leistet, insbesondere bei langen Dateien. Sie verwenden können $RANDOM, % wc -l, jot, sed -n(à la stackoverflow.com/a/6022431/563329 ) und bash - Funktionalität (Arrays, Befehl Umleitungen usw.) Ihre eigene definieren peekFunktion , die auf 5.000.000 Online-Dateien tatsächlich ausgeführt wird.
Isomorphismen

Antworten:


627

Verwenden Sie shufmit der -nOption , wie unten gezeigt, zu erhalten Nzufällige Linien:

shuf -n N input > output

2
Wenn Sie nur einen zufälligen Satz von Zeilen benötigen, nicht in zufälliger Reihenfolge, ist shuf sehr ineffizient (für große Dateien): Besser ist es, Reservoir-Sampling durchzuführen, wie in dieser Antwort .
Petrelharp

Ich habe dies auf einer 500M-Zeilendatei ausgeführt, um 1.000 Zeilen zu extrahieren, und es dauerte 13 Minuten. Auf die Datei wurde seit Monaten nicht mehr zugegriffen und sie befindet sich auf einem Amazon EC2 SSD-Laufwerk.
T. Brian Jones

Ist das also im Wesentlichen zufälliger als das sort -R?
Mona Jalal

1
@MonaJalal nein nur schneller, da es überhaupt keine Zeilen vergleichen muss.
Rogerdpack

Ergibt es schließlich mehr als einmal dieselbe Linie?
Frederick Nord

160

Sortieren Sie die Datei nach dem Zufallsprinzip und wählen Sie die ersten 100Zeilen aus:

$ sort -R input | head -n 100 >output

43
sortsortiert tatsächlich identische Zeilen zusammen. Wenn Sie also möglicherweise doppelte Zeilen haben und shuf(ein Gnu-Tool) installiert haben, ist es besser, diese zu verwenden.
Kevin

22
Außerdem wird dies definitiv dazu führen, dass Sie viel warten müssen, wenn Sie eine sehr große Datei haben - 80kk Zeilen -, während dies shuf -nziemlich sofort geschieht .
Rubens

28
sort -R ist nicht verfügbar unter Mac OS X (10.9)
Mirko Ebert

2
@ tfb785: sort -Rist wahrscheinlich GNU Option, installieren Sie GNU Coreutils. Übrigens shufist auch ein Teil von Coreutils.
JFS

1
@JFSebastian Der Code : sort -R input | head -n <num_lines>. Die Eingabedatei war 279 GB groß und hatte mehr als 2 Zeilen. Kann es aber nicht teilen. Der Punkt ist jedenfalls, dass Sie einige Zeilen mit Shuffle im Speicher behalten können, um die zufällige Auswahl der Ausgabe zu treffen. Durch Sortieren wird die gesamte Datei sortiert , unabhängig von Ihren Anforderungen.
Rubens

18

Nach einem Kommentar zur Shuf-Antwort mischte er 78 000 000 000 Zeilen in weniger als einer Minute.

Herausforderung angenommen...

Zuerst brauchte ich eine Datei mit 78.000.000.000 Zeilen:

seq 1 78 | xargs -n 1 -P 16 -I% seq 1 1000 | xargs -n 1 -P 16 -I% echo "" > lines_78000.txt
seq 1 1000 | xargs -n 1 -P 16 -I% cat lines_78000.txt > lines_78000000.txt
seq 1 1000 | xargs -n 1 -P 16 -I% cat lines_78000000.txt > lines_78000000000.txt

Das gibt mir eine Datei mit 78 Milliarden Zeilenumbrüchen ;-)

Nun zum Shuf-Teil:

$ time shuf -n 10 lines_78000000000.txt










shuf -n 10 lines_78000000000.txt  2171.20s user 22.17s system 99% cpu 36:35.80 total

Der Engpass war die CPU, die nicht mehrere Threads verwendete. Sie steckte 1 Kern zu 100% fest, die anderen 15 wurden nicht verwendet.

Python ist das, was ich regelmäßig benutze, also werde ich es verwenden, um dies schneller zu machen:

#!/bin/python3
import random
f = open("lines_78000000000.txt", "rt")
count = 0
while 1:
  buffer = f.read(65536)
  if not buffer: break
  count += buffer.count('\n')

for i in range(10):
  f.readline(random.randint(1, count))

Das brachte mich knapp eine Minute:

$ time ./shuf.py         










./shuf.py  42.57s user 16.19s system 98% cpu 59.752 total

Ich habe dies auf einem Lenovo X1 extreme 2. Generation mit dem i9 und Samsung NVMe gemacht, was mir viel Lese- und Schreibgeschwindigkeit gibt.

Ich weiß, dass es schneller werden kann, aber ich werde etwas Raum lassen, um andere auszuprobieren.

Zeilenzählerquelle : Luther Blissett

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.