Ich möchte beispielsweise die 10 häufigsten Wörter in einer Textdatei finden. Erstens sollte die Lösung für Tastenanschläge (mit anderen Worten: meine Zeit) optimiert sein. Zweitens für die Leistung. Hier ist, was ich bisher habe, um in die Top 10 zu kommen:
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
Ich könnte ein Java-, Python- usw.-Programm erstellen, in dem ich (Wort, Anzahl der Vorkommen) in einem Wörterbuch speichere und den Wert sortiere, oder ich könnte MapReduce verwenden, aber ich optimiere für Tastenanschläge.
Gibt es Fehlalarme? Gibt es einen besseren Weg?
Antwort1
Das ist so ziemlich die gängigste Methode, um die „N häufigsten Dinge“ zu finden, außer dass ein fehlt sort
und Sie ein unnötiges haben cat
:
tr -c '[:alnum:]' '[\n*]' < test.txt | sort | uniq -ci | sort -nr | head -10
sort
Wenn Sie vor dem kein einfügen, uniq -ci
erhalten Sie wahrscheinlich viele falsche Singleton-Wörter. uniq
führt nur eindeutige Zeilenfolgen aus, nicht die allgemeine Eindeutigkeit.
Sie können einen Trick anwenden, „Stoppwörter“. Wenn Sie sich einen englischen Text ansehen (Entschuldigung, wir sind einsprachig in Nordamerika), belegen Wörter wie „of“, „and“ und „the“ fast immer die ersten zwei oder drei Plätze. Sie möchten sie wahrscheinlich eliminieren. Die GNU Groff-Distribution enthält eine Datei mit dem Namen, eign
die eine ziemlich gute Liste von Stoppwörtern enthält. Meine Arch-Distribution hat /usr/share/groff/current/eign
, aber ich glaube, ich habe in alten Unix-Versionen auch /usr/share/dict/eign
oder gesehen./usr/dict/eign
Sie können Stoppwörter wie diese verwenden:
tr -c '[:alnum:]' '[\n*]' < test.txt |
fgrep -v -w -f -i /usr/share/groff/current/eign |
sort | uniq -ci | sort -nr | head -10
Ich vermute, dass in den meisten menschlichen Sprachen ähnliche „Stoppwörter“ aus aussagekräftigen Worthäufigkeitszählungen entfernt werden müssen, weiß aber nicht, wo ich Listen mit Stoppwörtern für andere Sprachen finden kann.
Das -w
Flag fgrep
aktiviert die Übereinstimmung ganzer Wörter. Dadurch werden falsche Ergebnisse bei Wörtern vermieden, die nur kurze Stoppwörter enthalten, wie „a“ oder „i“. Das -i
Flag aktiviert uniq
und fgrep
ignoriert die Groß-/Kleinschreibung beim Vergleichen von Wörtern.
Antwort2
Das funktioniert besser mit UTF-8:
$ sed -e 's/\s/\n/g' < test.txt | sort | uniq -c | sort -nr | head -10
Antwort3
Lasst uns AWK nutzen!
Diese Funktion listet die Häufigkeit jedes Worts in der bereitgestellten Datei in absteigender Reihenfolge auf:
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
}
Sie können es für Ihre Datei folgendermaßen aufrufen:
$ cat your_file.txt | wordfrequency
und für die Top 10 Wörter:
$ cat your_file.txt | wordfrequency | head -10
Quelle:AWK-Ward Ruby
Antwort4
Lasst uns Haskell verwenden!
Das entwickelt sich zu einem Sprachenkrieg, nicht wahr?
import Data.List
import Data.Ord
main = interact $ (=<<) (\x -> show (length x) ++ " - " ++ head x ++ "\n")
. sortBy (flip $ comparing length)
. group . sort
. words
Verwendung:
cat input | wordfreq
Alternative:
cat input | wordfreq | head -10