割と古典ですが、マルコフ連鎖の考え方を用いて、自動生成するスクリプトを書いてみました。入力した文章の単語同士の結合情報を重みづけをして「それっぽい文章」を生成してくれるやつです。以前からよく人工無能などでの実装で使われていますね。
ソースとなる文章をわかち書きに分割する処理に形態素解析コマンドの Chasen を使用しています。スクリプト本体は、文字分割の N-gram ではなく、単語分割したものを入力しますので、わかち書きが出せれば MeCab でも kakashi でも似たような感じでいけると思います。
#!/usr/bin/ruby | |
# coding: utf-8 | |
ts = {} | |
as = [] | |
(`chasen source.txt`).each_line do |line| | |
as.push line.split(/\t/)[0] | |
end | |
as.each_cons(2) do |ar| | |
if ts.key? ar.first | |
ts[ar.first].push(ar.last) | |
else | |
ts[ar.first] = [ar.last] | |
end | |
end | |
(0..10).each do | |
w = "」" | |
while w == "」" | |
w = ts["。"][rand(ts["。"].size)] | |
end | |
while true | |
printf w | |
if w == "。" || w == "」" | |
break | |
end | |
w = ts[w][rand(ts[w].size)] | |
end | |
puts "" | |
end |
単語リストに接尾単語リストを関連づけする方が精度が上がりますが、今回はちょっとしたテストコードですので、単語をリストで持たず1単語→接尾単語リストとして実装しています。
試しに、青空文庫で公開されている宮沢賢治の「銀河鉄道の夜」を入力してみると、次のように出力されました。
どうも今晩は見て、暗のところに見えるきれいだからこっちへかけて、 松や本の方はきちんとそろえて行きましょうと時計屋のしげみの底を 一つのやぐらが軽くひっぱましたともう着くころにふりうごかしました。 僕はそっちをもった。 孔雀が見えるのかたちが持っても手がだんだん横の旗を避けるようにした家でした。 いかがです。 美しい頬にふりを走っていました。 大きな黒い外套を揃えていましたよ。 ああそこでいて、おっかさんは空か。 わたくしたちが顔を大切に見えるのふしが云いました。 君もらわなかった。 ここはすぐ横手をつぶってるんなようにかかえられそうなことないか。 今日かがほとんどいちめんの口笛を擦りながら、私どものです。
意味はめちゃくちゃな文章ですが、スクリプトの短さの割にちょっと前の機械翻訳程度の和文は生成されますね。 Twitter や IRC, Slack などの bot や、音声合成システムの Open JTalk と組み合わせたら面白そうです。