ほどよく不自然な言語をつぶやき続けるスクリプト

Baidu さんちの不自然言語処理コンテスト用に何かネタを思いついたら作ってみようかな〜、とぼんやりしているうちに締め切りが過ぎていた。
と、残念がっていたらなんか締め切りが1日伸びたようなので、このまえ作っていた 不自然言語処理コンテストのコーパスを使って乱数作文するスクリプト を3-gram 以上に対応させつつ、出来るだけ長い文章をつぶやき続けるようにちょっと作り直してみた。

#! /usr/bin/env python
# -*- coding: utf-8 -*-
# endless_text.py : Endless Text Generator

import sys, time, codecs, random
# codec指定(DOS窓/リダイレクトの両方に対応)
if not sys.stdout.encoding:
    sys.stdout = codecs.getwriter('utf_8')(sys.stdout)

if len(sys.argv) != 2:
    print >>sys.stderr, "Usage: endless_text.py <n-gm file>"
    exit(1)
filename = sys.argv[1]

# read ngram file
stop_words = [u"</S>", u"<UNK>", u"<EMOJI_B0C>"]
ngram_dict = {}
for line in open(filename, "rb"):
    ngram_str, c_str = line.decode('utf-8').split('\t')
    ngram = ngram_str.split(' ')
    if ngram[-1] in stop_words: continue
    key = ' '.join(ngram[:-1])
    if key not in ngram_dict:
        ngram_dict[key] = {}
    ngram_dict[key][ngram[-1]] = -1 # 今回は頻度情報は使わず(長いほどよい)

# 前処理:「しっぽ」(続きのない系列)を切り離す
print len(ngram_dict)
exists_end = True
while exists_end:
    exists_end = False
    keys = ngram_dict.keys()
    for n_1gram_str in keys:
        n_1gram = n_1gram_str.split(' ')[1:] + [None]
        next_words = ngram_dict[n_1gram_str].keys()
        for word in next_words:
            n_1gram[-1] = word
            if ' '.join(n_1gram) not in ngram_dict:
                del ngram_dict[n_1gram_str][word]
        if len(ngram_dict[n_1gram_str]) == 0:
            del ngram_dict[n_1gram_str]
            exists_end = True
    print len(ngram_dict)

# つぶやく
start_words = [x for x in ngram_dict if x.startswith(u"<S>")]
c = 0
while True:
    words = random.choice(start_words).split(' ') # しゃべりだし
    print ' '.join(words[1:]),
    while True:
        next_words = ngram_dict[' '.join(words)]
        word = random.choice(next_words.keys()) # 次の言葉
        words = words[1:] + [word]
        print word,
        time.sleep(0.1)
        if next_words[word] == c: break # つぶやきがループしたら最初から
        next_words[word] = c
    print
    c += 1


自然言語処理コンテストの 2-gram 以上のコーパスを与えると、少し前処理をしたあと、「ほどよく不自然な言語」を延々つぶやき続ける。

python endless_text.py 4gm-a.txt


どのような言葉をつぶやくのか、もちろんご覧いただきたいところだが、コーパスに少々多々問題があって、結果をそのままコピペで貼ってしまった日には、検索エンジン経由でいろいろ間違った期待をいだいた方々が大挙してやってきてしまいそうだったので、画像にしたものを下に貼ってある。
しかも、これでも比較的穏当で無難な出力を選んである。というわけで endless_text.py の真の実力を見てみたい人は、不自然言語処理コンテストのコーパスを与えて実行してみてくれると。
ドコモのコーパスはでかいので、前処理にかなり時間がかかるが、その分多彩なおしゃべりを披露してくれる。あと、5-gram コーパスだとときどき「これは元の文章復元しちゃってる……よね?」と、Baidu の中の人が冷や汗をかいたりかかなかったり。固有名詞が出ちゃってるとかなりヤバい(苦笑)。




以前、「有向グラフから長くて尤もらしい系列を抽出する」というネタをやったことがあって、それをこのコーパスに使えば……という空想もしてたのだけど、そこまで手が回らなかったのが惜しかったのう。