Mische zwei parallele Textdateien

9

Ich habe zwei satzausgerichtete parallele Korpora (Textdateien) mit ungefähr 50 Millionen Wörtern. (aus dem Europarl-Korpus -> Parallelübersetzung von Rechtsdokumenten). Ich möchte jetzt die Zeilen der beiden Dateien mischen, aber beide auf die gleiche Weise. Ich wollte das mit gshuf (ich bin auf einem Mac) mit einer einzigen zufälligen Quelle erreichen.

gshuf --random-source /path/to/some/random/data file1
gshuf --random-source /path/to/some/random/data file2

Aber ich habe die Fehlermeldung erhalten end of file, weil anscheinend der zufällige Startwert alle Wörter enthalten muss, die die zu sortierende Datei enthält. Ist das wahr? Wenn ja, wie soll ich einen zufälligen Startwert erstellen, der meinen Anforderungen entspricht? Wenn nein, auf welche andere Weise könnte ich die Dateien parallel randomisieren? Ich dachte daran, sie zusammenzufügen, zufällig zu sortieren und dann wieder aufzuteilen. Dies scheint jedoch hässlich zu sein, da ich zuerst ein Trennzeichen finden müsste, das in den Dateien nicht vorkommt.

conipo
quelle
1
Sie haben diesen Fehler erhalten, weil Ihre random_file nicht genügend Bytes enthält ... Siehe random sources. Was pasteSie als Trennzeichen einig niedrigen ASCII - Zeichen verwenden könnten , die in den Dateien (wie das Auftreten unwahrscheinlich sind \x02, \x03...).
don_crissti
Okay, was auch immer ich randomisieren möchte, wenn ich / dev / urandom benutze, sollte ich gut gehen, oder? Der Pastenbegrenzer ist ein guter Tipp, danke!
Conipo

Antworten:

10

Ich weiß nicht, ob es eine elegantere Methode gibt, aber das funktioniert bei mir:

mkfifo onerandom tworandom threerandom
tee onerandom tworandom threerandom < /dev/urandom > /dev/null &
shuf --random-source=onerandom onefile > onefile.shuf &
shuf --random-source=tworandom twofile > twofile.shuf &
shuf --random-source=threerandom threefile > threefile.shuf &
wait

Ergebnis:

$ head -n 3 *.shuf
==> onefile.shuf <==
24532 one
47259 one
58678 one

==> threefile.shuf <==
24532 three
47259 three
58678 three

==> twofile.shuf <==
24532 two
47259 two
58678 two

Die Dateien müssen jedoch genau die gleiche Anzahl von Zeilen haben.


Die Dokumentation zu GNU Coreutils bietet auch eine gute Lösung für wiederholte Zufälligkeiten, die opensslals Startgenerator verwendet werden:

https://www.gnu.org/software/coreutils/manual/html_node/Random-sources.html#Random-sources

get_seeded_random()
{
  seed="$1"
  openssl enc -aes-256-ctr -pass pass:"$seed" -nosalt \
    </dev/zero 2>/dev/null
}

shuf -i1-100 --random-source=<(get_seeded_random 42)

Verwenden Sie jedoch einen besseren Startwert als "42", es sei denn, Sie möchten, dass auch andere Personen "Ihr" zufälliges Ergebnis reproduzieren können.

Frostschutz
quelle
Das funktioniert wie ein Zauber. Würde es Ihnen etwas ausmachen, die Schritte zu erklären, die Sie unternommen haben? Der Befehl tee stellt sicher, dass in allen drei Pipes dieselbe Zufallszahl gespeichert ist, oder? Warum muss es auch nach / dev / null ausgegeben werden? Und wird automatisch sichergestellt, dass genügend Bytes vorhanden sind und der end of fileFehler nicht auftritt?
Conipo
Das /dev/nullliegt daran, dass teeauch gedruckt wird stdout. Könnte > threerandomstattdessen verwenden, aber es ist schwieriger zu skripten. Die genannten Pipes erzeugen so viele zufällige Daten wie nötig, sodass Sie nicht vorher wissen müssen, wie viel Sie benötigen.
Frostschutz
Ok, und warum kann es dann nicht nur eine Pipe sein, die Sie als Zufallsquelle für alle 3 Shuffles nacheinander verwenden?
Conipo
2
Sie können nicht dreimal dieselben Daten aus einer Pipe lesen. Man muss irgendwie multiplexen und das teemacht ...
Frostschutz