y_uti のブログ

統計、機械学習、自然言語処理などに興味を持つエンジニアの技術ブログです

NLTK でランダム文生成

Python の NLTK を使って、ランダム文生成で遊んでみました。

学習に使うコーパスが必要なので wikipedia のデータを貰ってきます。「要約」が一番小さそうなので、それにしました。それでも 1.2GB くらいあります。

$ wget http://dumps.wikimedia.org/jawiki/latest/jawiki-latest-abstract.xml

データを眺めてみると、abstract タグの中を抽出すればよさそうです。XML をパーズしなくても行単位で切り出せそうなので、こんな感じで。ちなみに、これで 110MB くらいになりました。

$ grep '^<abstract>' jawiki-latest-abstract.xml | sed 's/^.*>\(.*\)<.*$/\1/' >abstract.txt

適当に小さくして mecab分かち書きします。先頭から連続して取ると分野が偏りそうな気がしたので、500 行ごとに 1000 文を取ってみました。

$ awk '{ if (NR % 500 == 0) print $0; if (NR / 500 == 1000) exit; }' abstract.txt | mecab -Owakati >wakati.txt

確認。ごみが残っているようですが、ここで頑張りだすと進まなくなるので、見なかったことにします。

$ head -n 5 wakati.txt
た なか 亜希 夫 ( た なか あき お 、 1 9 5 6 年 e - 1 day モーニング 連載 マンガ の 部屋 かぶ く 者 - ) は 、 日本 の 漫画 家 。
| Blood = B
_ _ NOTOC _ _
JPEG ( ジェイペグ 、 Joint Photographic Experts Group ) と は 、 コンピュータ など で 扱わ れる 静止 画像 の デジタル データ を 圧縮 する 方式 の ひとつ 。 または それ を つくっ た 組織 ( ISO / IEC JTC 1 / SC 2 9 / WG 1 、 Joint Photographic Experts Group ) の 略称 。 JPEG 方式 による 画像 ファイル に つけ られる 拡張 子 は jpg が 多く 使わ れ て いる が 、 jpeg 等 が 使わ れる 場合 も ある 。
都市 銀行 ( と し ぎんこう ) と は 、 普通 銀行 の 中 で 大都市 に 本店 を 構え 、 全国 に 支店 を 展開 し て いる 銀行 の こと と さ れる 。 なお 、 その 中 でも 更に 特別 に 大きな 銀行 を メガ バンク と 呼ぶ 。 略し て 都銀 。

さてようやく本題です。最後の text.generate(100) で、3-gram を作って 100 語のランダム文を表示してくれます。

>>> import codecs
>>> words = ' '.join([l.strip() for l in codecs.open('wakati.txt', 'r').readlines()]).split()
>>> from nltk.text import Text
>>> text = Text(words)
>>> text.generate(100)
Building ngram index...
た なか あき お 、 1 8 日 2 0 日 まで テレビ 新 広島
で 、 狭義 で は 、 新潟 県 上越 市 に 位置 する
大きな 小惑星 で ある 。 一番 艦 ま しゅうは 2 0 0 2
7 日 から 8月 1 2 日 ) ) は 青森 県 出身 の 落語 家
。 大阪 府 thumb | 2 5 , 8 3 1 日 - 1 9 2 年 。 thumb | 妹 |
愛称 = 埼玉 スタジアム ミリ ペン は 、 律令制
において 中務 省 に 位置 する 郡 で ある 盲腸  
ウマ

このメソッドは完全にブラックボックス化されていて、あまり遊べません。そこで、同じことを NgramModel を使って書いてみます。コンストラクタの第一引数で n-gram の n を指定できます。また、NgramModel の generate メソッドは、第二引数でコンテキストを指定できるようです。

>>> from nltk.model.ngram import NgramModel
>>> ngram = NgramModel(3, words)
>>> import warnings
>>> warnings.filterwarnings('ignore', '', UserWarning)
>>> print ''.join(ngram.generate(100, ['東京', 'とは']))
東京とは起草中で、都道府県に置かれている。|外部リンク=公式サイト・ノースカロライナ州ワールドリーグ『吉本もののけバラエティー妖怪ブッサイくん』(ラブねむれずにきみのよこがおずっとみていたオートバイのシリーズ車種である。NTTデータが提供している、加盟国間若しくはモデル租税条約を起草中で火星と木星の間で定義される祭り。松平伊豆守系大河内松平家7代。自然保護官(しぜんほごかん、

3, 4 行目で警告の表示を抑制していますが、これを書かないと generate したときに次のような警告がたくさん出てしまいました。

/usr/lib/python2.6/site-packages/nltk/probability.py:625: UserWarning: Probability distribution <SimpleGoodTuringProbDist based on 1 samples> sums to 0.74412446178823299; generate() is returning an arbitrary sample.
  " is returning an arbitrary sample." % (self, 1-p))