ファイル内で最も頻繁に使用される n 個の単語を検索する

ファイル内で最も頻繁に使用される n 個の単語を検索する

たとえば、テキスト ファイル内で最も一般的な 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 などのプログラムを作成して (単語、出現回数) を辞書に保存し、値を並べ替えることも、MapReduce を使用することもできますが、キーストロークを最適化します。

誤検知はありますか? もっと良い方法はあるでしょうか?

答え1

これは、「N 個の最も一般的なもの」を見つける最も一般的な方法ですが、 が欠落しておりsort、不必要な が生成されますcat

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

sortの前に を入れないと、uniq -ci おそらく誤った単一単語が多数生成されます。 は、 uniq行の連続のみが一意であり、全体的な一意性は保証されません。

「ストップワード」というトリックを使うといいかもしれません。英語のテキスト (申し訳ありませんが、ここでは北米の単一言語です) を見ている場合、「of」、「and」、「the」などの単語がほぼ常に上位 2 位または 3 位を占めます。おそらく、これらを削除したほうがよいでしょう。GNU Groff ディストリビューションeignには、ストップワードのかなり適切なリストを含む という名前のファイルがあります。私の Arch ディストリビューションには がありますが、古い Unix ではまたは/usr/share/groff/current/eignも見られたと思います。/usr/share/dict/eign/usr/dict/eign

ストップワードは次のように使用できます。

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

私の推測では、ほとんどの人間の言語では、意味のある単語の頻度カウントから同様の「ストップワード」を削除する必要があると思いますが、他の言語のストップワード リストをどこで入手できるかはわかりません。

フラグを-wオンにするとfgrep、単語全体の一致が有効になります。これにより、「a」や「i」などの短い終止符だけを含む単語の誤検出を回避できます。フラグをオンにすると、単語の比較時に大文字と小文字が無視され-iますuniqfgrep

答え2

これは utf-8 でより適切に動作します:

$ sed -e 's/\s/\n/g' < test.txt | sort | uniq -c | sort -nr | head  -10

答え3

AWKを使ってみましょう!

この関数は、指定されたファイル内で出現する各単語の頻度を降順でリストします。

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
}

次のようにファイル上で呼び出すことができます:

$ cat your_file.txt | wordfrequency

上位10単語は次のとおりです。

$ cat your_file.txt | wordfrequency | head -10

ソース:AWK ワード ルビー

答え4

Haskellを使ってみましょう!

これは言語戦争になりつつあるのではないですか?

import Data.List
import Data.Ord

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

使用法:

cat input | wordfreq

あるいは:

cat input | wordfreq | head -10

関連情報