設問1:トークンの出現頻度を集計してみよう!

CodeIQで作成した設問1

Python自然言語処理パッケージNLTKをインストールすること。以下のURLを参照して下さい。
http://www.nltk.org/

NLTKにはフリーの電子書籍を有する「グーテンベルク電子出版アーカイブ」プロジェクト
のデータが含まれています。nltkによるgutenbergのデータのダウンロードが必要です。
http://www.gutenberg.org/

gutenbergに収録されているジェーン・オースティンの「分別と多感」のテキストausten-sense.txtを読み込んで、テキスト内のトークン(単語)の出現頻度の一覧を作成してください。

トークンには、カンマ「,」、ピリオド「.」などの記号が含まれているため、アルファベット文字でのみ構成されるトークンだけを出力対象とします。アルファベットは全て小文字に置き換えて、NLTKのFreqDist関数を使って、トークンの頻度を集計してください。

出力ファイルはカンマ区切りのCSV形式で以下の通り。
頻度順(降順)で出力すること。
1カラム目 トーク
2カラム目 頻度
3カラム目 全体に占めるパーセンテージ(出力形式は%f)

to,4116,3.40918
the,4105,3.40006
of,3572,2.95859
(以下省略)

参考文献
・Steven Bird 「入門 自然言語処理オライリー・ジャパン
 http://www.amazon.co.jp/gp/product/4873114705
・上記の書籍の英語版はオンラインで読めます。
 Natural Language Processing with Python --- Analyzing Text with the Natural Language Toolkit
 Steven Bird, Ewan Klein, and Edward Loper
 O'Reilly Media, 2009.
 http://nltk.org/book/
 Kindle
 http://www.amazon.co.jp/gp/product/B0043D2E22

解答例1

[プログラム]

問題のプログラムのポイントは以下の3点です。

1. NLTKのインストールとデータのダウンロード
2. トークンの条件による絞り込み
3. DistFreqオブジェクトの使い方

NLTKからausten-sense.txtをダウンロードできたでしょうか。

トークンのリストを取得できたら、以下の様にアルファベットのみを含むトークンに
絞り、小文字化します。

text = [w.lower() for w in text0 if w.isalpha()]

Pythonでは、集合の数学記号 {x|x in A}
等のように1行でデータの抜き出しと変換を行う事できます。私も何年もPythonをやってきましたが、こんなにエレガントに書けるなんて長い間知りませんでした。
この書記法に慣れていきましょう。

トークンリストからFreqDistオブジェクトを生成し、ループを回して頻度を出力すれば終わりです。

問題では頻度順ソートについては書きませんでしたが、FreqDistオブジェクトの keys() メソッドは頻度の降順でキーのリストを出してくれるので、わざわざソートする必要はあ
りません。便利ですね。

プログラムの解答例は以下の通りです。

#!/usr/bin/python
# -*- coding: utf-8 -*-
#
#                           gutenberg.py
#

import nltk

i_file, o_file = 'austen-sense.txt', 'austen-sense.out'

### データのダウンロード ###
text0 = nltk.corpus.gutenberg.words(i_file)

### アルファベットのみを含むトークンを小文字化する ###
text = [w.lower() for w in text0 if w.isalpha()]

### FreqDistオブジェクト ###
fdist1 = nltk.FreqDist(text)
o_handle = open(o_file, 'w')
words = len(text)
for k in fdist1.keys():
    w = '%s,%d,%f\n' % (k, fdist1[k], 100.0*float(fdist1[k])/words)
    o_handle.write(w)

[出力結果で気づいた点]

出力結果は以下の通りです。

to,4116,3.40918
the,4105,3.40006
of,3572,2.95859
and,3491,2.89150
her,2551,2.11293
a,2092,1.73275
i,2004,1.65986
in,1979,1.63915
was,1861,1.54142
it,1757,1.45528
she,1613,1.33601
that,1385,1.14716
be,1305,1.08090
for,1262,1.04528
not,1248,1.03369
as,1221,1.01132
you,1191,0.98647
he,1108,0.91773
his,1021,0.84567
had,998,0.82662
with,992,0.82165
but,886,0.73385
at,839,0.69492
have,819,0.67836
is,760,0.62949
by,750,0.62121
s,701,0.58062
on,696,0.57648
elinor,685,0.56737
all,656,0.54335
so,644,0.53341
him,642,0.53175
my,628,0.52016
which,593,0.49117
could,578,0.47874
no,568,0.47046
marianne,566,0.46880
from,541,0.44810
mrs,530,0.43899
they,521,0.43153


目で見てみると、ほとんど英語ではto, the, and等の高頻度のトークンは意味を担う語ではなく、文法的な語が多い事に気づきます。。ElinorとMarianneはこの小説にでてくる登場人物の名前です。呼びかけや説明文で、人名がでてくるは当然かもしれません。
人名以外に、この小説の特徴を表すトークンを見つけるのにはもう少し解析が必要なようですね。

トップ50の累積頻度をfdist1.plot(50, cumulative=True)で表示してみると、以下の様に
なります。

テキストの全語数が120733なので60000/120733=50.0%となり、たった50の語が半数を占めている事になります。