Я хочу найти, скажем, 10 самых распространенных слов в текстовом файле. Во-первых, решение должно быть оптимизировано для нажатия клавиш (другими словами - мое время). Во-вторых, для исполнения. Вот что у меня есть, чтобы получить топ-10:
cat test.txt | tr -c '[:alnum:]' '[\n*]' | uniq -c | sort -nr | head -10
6 k
2 g
2 e
2 a
1 r
1 k22
1 k
1 f
1 eeeeeeeeeeeeeeeeeeeee
1 d
Я мог бы создать программу на языке Java, Python и т. Д., В которой я храню (word, numberOfOccurences) в словаре и сортирую значение, или я мог бы использовать MapReduce, но я оптимизирую нажатия клавиш.
Есть ли ложные срабатывания? Есть ли способ лучше?
command-line
shell-script
Лукаш Мадон
источник
источник
Ответы:
Это довольно распространенный способ найти «N самых распространенных вещей», за исключением того, что вы пропустили a
sort
, и у вас есть подарокcat
:Если вы не вставите
sort
перед этим,uniq -c
вы, вероятно, получите много ложных синглтон-слов.uniq
делает только уникальные линии, а не уникальность.РЕДАКТИРОВАТЬ: я забыл трюк, "стоп-слова". Если вы смотрите на текст на английском языке (извините, здесь говорят на одноязычном языке для Северной Америки), такие слова, как "of", "и", "the", почти всегда занимают верхние два или три места. Вы, вероятно, хотите устранить их. В дистрибутиве GNU Groff есть названный файл,
eign
который содержит довольно приличный список стоп-слов. Мой Arch дистрибутив есть/usr/share/groff/current/eign
, но я думаю, что я также видел/usr/share/dict/eign
или/usr/dict/eign
в старых Unixes.Вы можете использовать стоп-слова, как это:
Я предполагаю, что большинство человеческих языков нуждаются в аналогичных «стоп-словах», удаленных из значимых значений частоты слов, но я не знаю, где предложить другие языки, чтобы остановить список слов.
РЕДАКТИРОВАТЬ:
fgrep
следует использовать-w
команду, которая включает сопоставление целых слов. Это позволяет избежать ложных срабатываний в словах, которые просто содержат короткие остановки, такие как «а» или «я».источник
cat
существенные потери производительности? Мне нравится синтаксис канала. Что делает * in '[\ n *]'?find
выводе? То есть разделять слова/
вместо пробельных символов и тому подобное.find somewhere optoins | tr '/' '\n' | sort | uniq -c | sort -k1.1nr | head -10
Это работает лучше с utf-8:
источник
Давайте использовать AWK!
Эта функция перечисляет частоту каждого слова, встречающегося в предоставленном файле в порядке убывания:
Вы можете назвать это в своем файле следующим образом:
и для лучших 10 слов:
Источник: AWK-опека Руби
источник
Давайте использовать Haskell!
Это превращается в языковую войну, не так ли?
Использование:
В качестве альтернативы:
источник
sort | uniq -c | sort -nr
.Text
илиByteString
вместо этого, что так же просто, как импортировать квалифицированную и ставить префикс перед функциями с квалификатором.Примерно так должно работать с использованием общедоступного python:
Это предполагает слово в строке. Если их больше, расщепление должно быть легким.
источник
cat README.md | python -c 'import collections, sys, pprint; pprint.pprint(collections.Counter(sys.stdin));'
Это классическая проблема, которая получила некоторый резонанс в 1986 году, когда Дональд Кнут реализовал быстрое решение с помощью попыток хэширования в программе длиной в 8 страниц, чтобы проиллюстрировать свою технику грамотного программирования, в то время как Дуг Макилрой, крестный отец каналов Unix, ответил с Это было не так быстро, но сделало работу:
Конечно, решение Макилроя имеет временную сложность O (N log N), где N - общее количество слов. Есть гораздо более быстрые решения. Например:
Вот реализация C ++ с верхней границей сложности времени O ((N + k) log k), обычно - почти линейной.
Ниже приведена быстрая реализация Python с использованием хеш-словарей и кучи с временной сложностью O (N + k log Q), где Q - количество уникальных слов:
Вот это очень быстро раствор в Rust Андерс Kaseorg.
Сравнение времени процессора (в секундах):
Заметки:
источник