Gibt es einen Linux-Befehl, mit dem eine Teilmenge einer Datei abgetastet werden kann? Eine Datei enthält beispielsweise eine Million Zeilen, und wir möchten nur eintausend Zeilen aus dieser Datei zufällig auswählen.
Für zufällig meine ich, dass jede Zeile die gleiche Wahrscheinlichkeit hat, ausgewählt zu werden und keine der ausgewählten Zeilen sich wiederholt.
head
und tail
kann eine Teilmenge der Datei aber nicht zufällig auswählen. Ich weiß, dass ich dazu immer ein Python-Skript schreiben kann, aber ich frage mich, ob es einen Befehl für diese Verwendung gibt.
command-line
files
command
Clwen
quelle
quelle
Antworten:
Der
shuf
Befehl (Teil von coreutils) kann dies tun:Zumindest für nicht-alte Versionen (hinzugefügt in einem Commit von 2013 ), die bei Bedarf eine Reservoir-Abtastung verwenden, was bedeutet, dass der Speicher nicht knapp werden sollte und ein schneller Algorithmus verwendet wird.
quelle
sort
es sich im selben Abschnitt befindet und eindeutig keine sortierte Eingabe erfordert.shuf
Coreutils wurde in der Version eingeführt6.0 (2006-08-15)
, und ob Sie es glauben oder nicht, einige vernünftigerweise gebräuchliche Systeme (insbesondere CentOS 6.5) haben diese Version nicht: - |shuf -n
führt eine Reservoir-Abtastung durch, zumindest wenn die Eingabe größer als 8 KB ist. Die ermittelte Größe ist Benchmarks besser. Siehe den Quellcode (z. B. unter github.com/coreutils/coreutils/blob/master/src/shuf.c#L46 ). Entschuldigen Sie diese sehr späte Antwort. Anscheinend ist das seit 6 Jahren neu.Wenn Sie eine sehr große Datei haben (was ein häufiger Grund ist, ein Beispiel zu nehmen), werden Sie feststellen, dass:
shuf
erschöpft den Speicher$RANDOM
funktioniert nicht richtig, wenn die Datei mehr als 32767 Zeilen enthältWenn Sie nicht "genau" n abgetastete Linien benötigen, können Sie ein Verhältnis wie das folgende abtasten:
cat input.txt | awk 'BEGIN {srand()} !/^$/ { if (rand() <= .01) print $0}' > sample.txt
Dies verwendet konstanten Speicher , tastet 1% der Datei ab (wenn Sie die Anzahl der Zeilen der Datei kennen, können Sie diesen Faktor anpassen, um eine begrenzte Anzahl von Zeilen abzutasten) und funktioniert mit jeder Dateigröße, dies wird jedoch nicht der Fall sein Rückgabe eines genauen Anzahl von Zeilen zurück, nur ein statistisches Verhältnis.
Hinweis: Der Code stammt von: https://stackoverflow.com/questions/692312/randomly-pick-lines-from-a-file-with-slurping-it-with-unix
quelle
$RANDOM
funktionieren bei Dateien mit mehr als 32767 Zeilen nicht ordnungsgemäß. Die Aussage „Mit$RANDOM
wird nicht die gesamte Datei erreicht“ ist etwas weit gefasst.awk
ist ressourcenschonender alsshuf
Ähnlich wie bei der probabilistischen Lösung von @ Txangel, jedoch fast 100x schneller.
Wenn Sie eine hohe Leistung und eine genaue Stichprobengröße benötigen und gerne mit einer Stichprobenlücke am Ende der Datei leben, können Sie wie folgt vorgehen (Beispiel: 1000 Zeilen aus einer 1-Meter-Datei):
.. oder in der Tat eine zweite Beispielmethode anstelle von verketten
head
.quelle
Wenn der
shuf -n
Trick bei großen Dateien zu wenig Speicher hat und Sie immer noch ein Beispiel mit fester Größe benötigen und ein externes Dienstprogramm installiert werden kann, versuchen Sie es mit sample :Die Einschränkung ist, dass die Probe (1000 Zeilen im Beispiel) in den Speicher passen muss.
Haftungsausschluss: Ich bin der Autor der empfohlenen Software.
quelle
/usr/local/bin
Vorgänger/usr/bin/
auf dem Weg haben, ist es wichtig, dass macOS einen eingebauten Call-Stack-Sampler enthältsample
, der etwas völlig anderes ausführt/usr/bin/
.Ich kenne keinen einzelnen Befehl, der das tun könnte, was Sie verlangen, aber hier ist eine Schleife, die ich zusammengestellt habe, um den Job zu erledigen:
sed
wird bei jedem der 1000 Durchgänge eine zufällige Linie aufnehmen. Möglicherweise gibt es effizientere Lösungen.quelle
$RANDOM
hat eine Reichweite zwischen 0 und 32767. So werden Sie nicht eine gut Verbreitung Zeilennummern erhalten.Sie können den folgenden Code in einer Datei speichern (zum Beispiel randextract.sh) und ausführen als:
---- DATEI ANFANGEN ----
---- END FILE ----
quelle
$RANDOM$RANDOM
es werden keine Zufallszahlen im gesamten Bereich von „0 bis 3276732767“ generiert (z. B. 1000100000, aber nicht 1000099999).Wenn Sie die Anzahl der Zeilen in der Datei kennen (wie 1e6 in Ihrem Fall), können Sie Folgendes tun:
Wenn nicht, können Sie immer tun
Das würde zwei Durchgänge in der Datei machen, aber immer noch vermeiden, die gesamte Datei im Speicher zu speichern.
Ein weiterer Vorteil gegenüber GNU
shuf
ist, dass die Reihenfolge der Zeilen in der Datei beibehalten wird.Beachten Sie, dass davon ausgegangen
n
wird, wie viele Zeilen die Datei enthält. Wenn Siep
aus den erstenn
Zeilen der Datei (die möglicherweise mehr Zeilen enthält) drucken möchten , müssen Sieawk
an dern
th- Zeile wie folgt anhalten :quelle
Ich verwende awk gerne, wenn ich eine Kopfzeile beibehalten möchte und wenn das Beispiel ein ungefährer Prozentsatz der Datei sein kann. Funktioniert für sehr große Dateien:
quelle
Oder so:
Von der Bash-Manpage:
quelle
Wenn die Dateigröße nicht sehr groß ist, können Sie die Option Zufällig sortieren verwenden. Das dauert etwas länger als shuf, aber es ordnet die gesamten Daten nach dem Zufallsprinzip. Sie können also ganz einfach Folgendes tun, um head wie gewünscht zu verwenden:
Dies würde die Datei nach dem Zufallsprinzip sortieren und Ihnen die ersten 1000 Zeilen geben.
quelle
Wie in der akzeptierten Antwort erwähnt,
shuf
unterstützt GNUshuf -n
ziemlich gut einfache Zufallsstichproben ( ). Wenn Stichprobenmethodenshuf
erforderlich sind, die über die von unterstützten Methoden hinausgehen , ziehen Sie tsv-sample von eBay TSV Utilities in Betracht . Es werden mehrere zusätzliche Stichprobenmodi unterstützt, einschließlich gewichteter Zufallsstichproben, Bernoulli-Stichproben und eindeutiger Stichproben. Die Leistung ist ähnlich wie bei GNUshuf
(beide sind recht schnell). Haftungsausschluss: Ich bin der Autor.quelle