encontrar n palavras mais frequentes em um arquivo

31

Eu quero encontrar, digamos, 10 palavras mais comuns em um arquivo de texto. Em primeiro lugar, a solução deve ser otimizada para pressionamentos de tecla (em outras palavras - meu tempo). Em segundo lugar, pelo desempenho. Aqui está o que eu tenho até agora para chegar ao top 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

Eu poderia fazer um programa java, python etc. onde eu armazeno (word, numberOfOccurences) em um dicionário e classifico o valor ou eu poderia usar o MapReduce, mas eu otimizo as teclas digitadas.

Existe algum falso positivo? Existe uma maneira melhor?

    
por Lukasz Madon 24.06.2012 / 02:07

5 respostas

44

Essa é praticamente a maneira mais comum de encontrar "N coisas mais comuns", exceto que você está perdendo um sort e você tem um cat :

gratuito
tr -c '[:alnum:]' '[\n*]' < test.txt | sort | uniq -c | sort -nr | head  -10

Se você não colocar um sort antes do uniq -c , você provavelmente obterá muitas palavras com falsos singletons. uniq apenas executa execuções únicas de linhas, não unicidade geral.

EDIT: Eu esqueci um truque, "pare de falar". Se você está olhando para o texto em inglês (desculpe, monolíngüe norte-americano aqui), palavras como "of", "and", "the" quase sempre ocupam os dois ou três primeiros lugares. Você provavelmente quer eliminá-los. A distribuição GNU Groff tem um arquivo chamado eign , que contém uma lista bastante decente de palavras paradas. A distro do My Arch tem /usr/share/groff/current/eign , mas acho que também vi /usr/share/dict/eign ou /usr/dict/eign em antigos Unixes.

Você pode usar palavras como esta:

tr -c '[:alnum:]' '[\n*]' < test.txt |
fgrep -v -w -f /usr/share/groff/current/eign |
sort | uniq -c | sort -nr | head  -10

Meu palpite é que a maioria das linguagens humanas precisa de "palavras de parada" semelhantes removidas das contagens de frequência de palavras significativas, mas não sei onde sugerir que outros idiomas parem de listar palavras.

EDIT: fgrep deve usar o comando -w , que ativa a correspondência de palavras inteiras. Isso evita falsos positivos em palavras que contêm apenas trabalhos curtos, como "a" ou "i".

    
por 24.06.2012 / 02:35
8

Isso funciona melhor com o utf-8:

$ sed -e 's/\s/\n/g' < test.txt | sort | uniq -c | sort -nr | head  -10
    
por 28.08.2013 / 23:45
7

Vamos usar o AWK!

Esta função lista a frequência de cada palavra que ocorre no arquivo fornecido na ordem Decrescente:

function wordfrequency() {
  awk '
     BEGIN { FS="[^a-zA-Z]+" } {
         for (i=1; i<=NF; i++) {
             word = tolower($i)
             words[word]++
         }
     }
     END {
         for (w in words)
              printf("%3d %s\n", words[w], w)
     } ' | sort -rn
}

Você pode chamá-lo no seu arquivo assim:

$ cat your_file.txt | wordfrequency

e para as 10 principais palavras:

$ cat your_file.txt | wordfrequency | head -10

Fonte: Ruby do AWK-ward

    
por 15.12.2014 / 23:57
5

Vamos usar o Haskell!

Isso está se transformando em uma guerra de idiomas, não é?

import Data.List
import Data.Ord

main = interact $ (=<<) (\x -> show (length x) ++ " - " ++ head x ++ "\n")
                . sortBy (flip $ comparing length)
                . group . sort
                . words

Uso:

cat input | wordfreq

Alternativamente:

cat input | wordfreq | head -10
    
por 03.10.2015 / 05:33
1

Algo como isso deve funcionar usando python, que é comumente disponível:

cat slowest-names.log | python -c 'import collections, sys; print collections.Counter(sys.stdin);'

Isso pressupõe palavra por linha. Se houver mais, a divisão também deve ser fácil.

    
por 23.05.2016 / 09:26