Mélangez deux fichiers texte parallèles

9

J'ai deux corpus parallèles alignés sur des phrases (fichiers texte) avec environ 50 millions de mots. (du corpus Europarl -> traduction parallèle de documents juridiques). Je voudrais maintenant mélanger les lignes des deux fichiers, mais les deux de la même manière. Je voulais aborder cela en utilisant gshuf (je suis sur un Mac) en utilisant une source aléatoire unique.

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

Mais j'ai reçu le message d'erreur end of file, car apparemment la graine aléatoire doit contenir tous les mots que contient le fichier à trier. Est-ce vrai? Si oui, comment créer une graine aléatoire adaptée à mes besoins? Si non, de quelle autre manière pourrais-je randomiser les fichiers en parallèle? J'ai pensé à les coller ensemble, à les randomiser puis à les séparer à nouveau. Cependant, cela semble moche car je devrais d'abord trouver un délimiteur qui ne se produit pas dans les fichiers.

conipo
la source
1
Vous avez cette erreur car votre random_file ne contient pas suffisamment d'octets ... Voir random sources. En ce qui concerne paste, vous pouvez utiliser comme délimiteur un caractère de faible ascii qui ne se produira probablement pas dans vos fichiers (comme \x02, \x03...).
don_crissti
D'accord, quoi que je veuille randomiser, si j'utilise / dev / urandom, je devrais être prêt à partir, non? Le délimiteur de pâte est un bon conseil, merci!
conipo

Réponses:

10

Je ne sais pas s'il existe une méthode plus élégante mais cela fonctionne pour moi:

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

Résultat:

$ 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

Mais les fichiers doivent avoir exactement le même nombre de lignes.


La documentation GNU Coreutils fournit également une bonne solution pour l'aléatoire répété en utilisant opensslcomme générateur aléatoire prédéfini:

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)

Cependant, pensez à utiliser une meilleure graine que "42", à moins que vous ne vouliez que quelqu'un d'autre puisse également reproduire "votre" résultat aléatoire.

frostschutz
la source
Cela fonctionne comme un charme. Pourriez-vous expliquer les mesures que vous avez prises? La commande tee garantit que le même nombre aléatoire est stocké dans les trois canaux, non? Pourquoi doit-il également sortir vers / dev / null? Et est-il automatiquement garanti qu'il y a suffisamment d'octets et que l' end of fileerreur ne se produit pas?
conipo
C'est /dev/nullparce teequ'imprime également sur stdout. Peut être utilisé à la > threerandomplace, mais il est plus difficile de l'écrire. Les canaux nommés produiront autant de données aléatoires que nécessaire, vous n'avez donc pas besoin de savoir à l'avance de combien vous aurez besoin.
frostschutz
D'accord, et pourquoi ne peut-il pas s'agir alors d'une seule pipe que vous utilisez comme source aléatoire pour les 3 shuffles l'un après l'autre?
conipo
2
Vous ne pouvez pas lire les mêmes données trois fois à partir d'un tuyau. Vous devez en quelque sorte multiplexer et c'est ce qui teefait ...
frostschutz