Перемешать два параллельных текстовых файла

9

У меня есть две параллельные тела (текстовые файлы) с выравниванием по предложениям, содержащие около 50 миллионов слов. (из Europarl corpus -> параллельный перевод юридических документов). Теперь я хотел бы перемешать строки двух файлов, но оба одинаково. Я хотел подойти к этому, используя gshuf (я на Mac), используя один уникальный случайный источник.

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

Но я получил сообщение об ошибке end of file, потому что, очевидно, случайное начальное число должно содержать все слова, которые содержит файл для сортировки. Это правда? Если да, то как мне создать случайное семя, подходящее для моих нужд? Если нет, каким образом можно параллельно рандомизировать файлы? Я думал о склеивании их, рандомизации и последующем разделении. Тем не менее, это кажется уродливым, так как мне нужно было бы сначала найти разделитель, который не встречается в файлах.

conipo
источник
1
Вы получили эту ошибку, потому что ваш random_file не содержит достаточно байтов ... Видите random sources. Что касается paste, вы можете использовать в качестве разделителя какой-нибудь символ низкого качества, который вряд ли будет встречаться в ваших файлах (например \x02, \x03...).
don_crissti
Хорошо, все, что я хочу рандомизировать, если я использую / dev / urandom, у меня все получится, верно? Разделитель пасты - хороший совет, спасибо!
Конипо

Ответы:

10

Я не знаю, есть ли более элегантный метод, но это работает для меня:

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

Результат:

$ 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

Но файлы должны иметь одинаковое количество строк.


Документация GNU Coreutils также предоставляет отличное решение для повторяющихся случайностей с использованием opensslгенератора случайных чисел:

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)

Тем не менее, рассмотрите возможность использования лучшего семени, чем «42», если только вы не хотите, чтобы кто-либо еще мог воспроизвести «ваш» случайный результат.

frostschutz
источник
Это работает как шарм. Не могли бы вы объяснить, какие шаги вы предприняли? Команда tee гарантирует, что одно и то же случайное число сохраняется во всех трех каналах, верно? Почему он также должен выводиться в / dev / null? И автоматически ли обеспечивается достаточное количество байтов и end of fileошибка не возникает?
Конипо
Это /dev/nullпотому, что teeтакже печатает stdout. Можно использовать > threerandomвместо этого, но это сложнее для сценария. Именованные каналы будут генерировать столько случайных данных, сколько необходимо, поэтому вам не нужно заранее знать, сколько вам понадобится.
frostschutz
Хорошо, а почему тогда не может быть просто один канал, который вы используете в качестве случайного источника для всех трех перемешиваний один за другим?
conipo
2
Вы не можете прочитать одни и те же данные три раза из одного канала. Вы должны как-то мультиплексировать, и вот что teeделает ...
frostschutz