Quiero encontrar, digamos, las 10 palabras más comunes en un archivo de texto. En primer lugar, la solución debe optimizarse para las pulsaciones de teclas (en otras palabras, mi tiempo). En segundo lugar, por la actuación. Esto es lo que tengo hasta ahora para estar entre los 10 primeros:
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
Podría crear un programa java, python, etc. donde almaceno (palabra, número de ocurrencias) en un diccionario y ordene el valor o podría usar MapReduce, pero optimizo para las pulsaciones de teclas.
¿Hay algún falso positivo? ¿Existe una mejor manera?
Respuesta1
Esa es prácticamente la forma más común de encontrar "N cosas más comunes", excepto que te falta un sort
y tienes un gratuito cat
:
tr -c '[:alnum:]' '[\n*]' < test.txt | sort | uniq -ci | sort -nr | head -10
Si no coloca un sort
antes, uniq -ci
probablemente obtendrá muchas palabras únicas falsas. uniq
solo hace tiradas únicas de líneas, no unicidad general.
Quizás quieras utilizar un truco: "palabras vacías". Si estás mirando texto en inglés (lo siento, aquí es monolingüe norteamericano), palabras como "of", "and", "the" casi siempre ocupan los dos o tres primeros lugares. Probablemente quieras eliminarlos. La distribución GNU Groff tiene un archivo nombrado eign
que contiene una lista bastante decente de palabras vacías. Mi distribución Arch tiene /usr/share/groff/current/eign
, pero creo que también lo he visto /usr/share/dict/eign
en /usr/dict/eign
Unixes antiguos.
Puedes utilizar palabras vacías como esta:
tr -c '[:alnum:]' '[\n*]' < test.txt |
fgrep -v -w -f -i /usr/share/groff/current/eign |
sort | uniq -ci | sort -nr | head -10
Supongo que la mayoría de los idiomas humanos necesitan "palabras vacías" similares eliminadas de los recuentos de frecuencia de palabras significativas, pero no sé dónde sugerir que se obtengan listas de palabras vacías de otros idiomas.
La -w
bandera activada fgrep
permite la coincidencia de palabras completas. Esto evita falsos positivos en palabras que simplemente contienen palabras breves, como "a" o "i". La -i
bandera está activada uniq
e fgrep
ignora mayúsculas y minúsculas al comparar palabras.
Respuesta2
Esto funciona mejor con utf-8:
$ sed -e 's/\s/\n/g' < test.txt | sort | uniq -c | sort -nr | head -10
Respuesta3
¡Usemos AWK!
Esta función enumera la frecuencia de cada palabra que aparece en el archivo proporcionado en orden descendente:
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
}
Puedes llamarlo en tu archivo de esta manera:
$ cat your_file.txt | wordfrequency
y para las 10 palabras principales:
$ cat your_file.txt | wordfrequency | head -10
Fuente:Ruby pupilo de AWK
Respuesta4
¡Usemos Haskell!
Esto se está convirtiendo en una guerra de idiomas, ¿no?
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