不自然言語処理コンテストのコーパスで乱数作文

Baidu さんの不自然言語処理コンテスト( http://www.baidu.jp/unlp/ )が始まったそうで。
5-gram までのコーパスも配布ということでとりあえず応募するしないはおいといてダウンロードダウンロード……。
2-gram でマルコフ連鎖で文章生成って誰でも考えるよなあ。サンプルスクリプトもあるし、早い者勝ちだよなあ。


というわけでさっくり書いてみた。サンプルスクリプトをちょこちょこっと削って、ちょこちょこっと足しただけ。numpy 使ってます。

import sys, codecs, numpy
sys.stdout = codecs.getwriter('utf_8')(sys.stdout)

if len(sys.argv) != 2:
    print >>sys.stderr, "Usage: randomtext.py <2gm file>"
    exit(1)

bgm_fn = sys.argv[1]                         # 2gm filename

bigram = {}
bigram_prob = {}

stopcontexts = [u"<S>", u"</S>", u"<UNK>"]

# read bigram file
for line in open(bgm_fn, "rb"):
    bgm_str, c_str = line.decode('utf-8').split('\t')
    w1, w2 = bgm_str.split(' ')
    c = int(c_str[:-1])
    if w1 not in bigram:
        bigram[w1] = []
        bigram_prob[w1] = []
    bigram[w1].append(w2)
    bigram_prob[w1].append(c)

for w in bigram_prob:
    amount = sum(bigram_prob[w])
    bigram_prob[w] = numpy.array(bigram_prob[w], dtype=float) / amount

for j in range(100):
  text = []
  word = u"<S>"
  for i in range(100):
      word = bigram[word][numpy.random.multinomial(1, bigram_prob[word]).argmax()]
      if word in stopcontexts: break
      text.append(word)
      if word not in bigram: break
  if len(text) >= 10: print "".join(text)

ドコモのデータが最初なぜか1行も読み込めなくてハマったのが一番時間かかったくらい(先頭が ^Z で始まってる)。
結果から一部。

確かに近いわ(え|きせかと日本海海戦と言いつつ、チェックを書く
※画像のがお見逃しなくていきます。
6では乗り越えてお金を入力した花のジャニーズソング着メロ/健康ダイエット♪桜。
読み手を追いかけている場所が相性占い<EMOJI_80A>無料出会い系サイトに行ってよかったです
携帯用飲み、あのエ、可能です。
せめてこれは通常の世の中にすごかった。
<EMOJI_81C>アニメ着うた・・登録|3月31)純がアツイも見た
そのリンクをリンクタグからログイン|和歌山出会い系サイト様が、賢い主婦の誓いの傷ばかりの紹介!!
道(メアド非公開設定の子竜と答えが自分の一息だよね~(何でも食べるの右のお知らせ
長門・来店不要なものがめっちゃいいのに、快適な方が見えちゃってましたよ
【早特上への行の登録したぜ…必見!
<EMOJI_526>電話でバカンスを狂わせるような場所で稼いじゃないので、チャンピオンのアバチャ

なんか普通にこういう文章書いてる人い……ないか。さすがに。
3-gram ならもうちょっとよくなるかも。