Embaralhe dois arquivos de texto paralelos

9

Eu tenho dois corpora paralelos alinhados por sentenças (arquivos de texto) com cerca de 50 mil palavras. (do Europarl corpus -> tradução paralela de documentos legais). Agora eu gostaria de embaralhar as linhas dos dois arquivos, mas ambos da mesma maneira. Eu queria abordar isso usando gshuf (estou em um Mac) usando uma fonte aleatória única.

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

Mas recebi a mensagem de erro end of file, porque aparentemente a semente aleatória precisa conter todas as palavras que o arquivo a ser classificado contém. Isso é verdade? Se sim, como devo criar uma semente aleatória que seja boa para minhas necessidades? Se não, de que outra maneira eu poderia aleatoriamente os arquivos em paralelo? Pensei em colá-los juntos, aleatoriamente e depois me separar novamente. No entanto, isso parece feio, pois eu precisaria primeiro encontrar um delimitador que não ocorra nos arquivos.

conipo
fonte
1
Você recebeu esse erro porque seu arquivo random_file não contém bytes suficientes ... Veja random sources. Quanto a paste, você pode usar como delimitador algum caractere de baixo ASCII que é improvável que ocorra em seus arquivos (como \x02, \x03...).
don_crissti
Tudo bem, o que eu quiser aleatoriamente, se eu usar / dev / urandom, eu devo estar pronto, certo? O delimitador de pasta é uma boa dica, obrigado!
conipo 7/08/15

Respostas:

10

Não sei se existe um método mais elegante, mas isso funciona para mim:

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

Resultado:

$ 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

Mas os arquivos devem ter exatamente o mesmo número de linhas.


A documentação do GNU Coreutils também fornece uma boa solução para aleatoriedade repetida usando opensslcomo um gerador aleatório semeado:

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)

No entanto, considere usar uma semente melhor que "42", a menos que você queira que mais alguém possa reproduzir "seu" resultado aleatório também.

frostschutz
fonte
Isso funciona como um encanto. Você se importaria de explicar os passos que tomou? O comando tee garante que o mesmo número aleatório seja armazenado nos três tubos, certo? Por que ele também precisa gerar para / dev / null? E é garantido automaticamente que haja bytes suficientes e que o end of fileerro não ocorra?
conipo 6/08/15
Isso /dev/nullocorre porque teetambém imprime em stdout. Poderia usar, > threerandommas é mais difícil de fazer scripts. Os pipes nomeados produzirão tantos dados aleatórios quanto necessários, para que você não precise saber de antemão quanto precisará.
Frostschutz 6/08
Ok, e por que não pode ser apenas um canal que você usa como fonte aleatória para todos os três shuffles, um após o outro?
conipo 6/08/15
2
Você não pode ler os mesmos dados três vezes em um pipe. Você tem que multiplex de alguma forma e isso é o que teefaz ...
frostschutz