NMeCab で形態素解析が簡単に行えるようになったので、何となくマルコフ連鎖での文章生成を選びました。少し時間かけて C# で実装したので、作成したコードを GitHub に置いておきました。
デフォルトでは MarkovKey クラス内で N = 2 としているので、2 次マルコフ連鎖になります。
マルコフ連鎖については説明を省略したいので、Wikipedia のリンクを貼っておきます。
今回、過去 2 つ分の単語を参照しているので N 次ということです。
少しだけコードの解説をしておきます。基本的にメインとなるのは MarkovDictionary クラスで、このクラスに用意してある AddSentence と BuildSentence メソッドを使うだけです。
var markovDic = new MarkovDictionary(); markovDic.AddSentence(new[] { "今日", "の", "天気", "は", "晴れ", "です。" }); markovDic.AddSentence(new[] { "明日", "の", "天気", "は", "雨", "です。" }); for (int i = 0; i < 10; i++) { Console.WriteLine(string.Join(" / ", markovDic.BuildSentence())); }
AddSentence メソッドで 2 つの文を辞書に投入し、10 回文章を生成するコードになります。
とても簡単な例ですが、このコードを実行すると以下のように文が出力されます。
AddSentence メソッドで追加した文とは異なるパターンが出力されていることが分かります。
大量に形態素解析した結果を追加していけば、もっとランダムな文章が生成されるはずです。なのでデータソースを用意して、後は前回の NMeCab の結果を使う形になります。
これは自分のツイートを形態素解析した結果を MarkovDictionary に投入し、15 個生成した例です。データ数が 1500 ほどしか無いのでバリエーションが少ないですが、そこまで意味不明にはなってないです。
実装について
MarkovDictionary は内部に Dictionary を持つ単純なクラスで、肝はキーとなる MarkovKey クラスの方です。
MarkovKey クラスは中で過去 2 つ分の単語を持っていて、それが Dictionary のキーとして動作します。なので、基本的には直前のキーを Push メソッドで更新して Dictionary に追加していくだけという、とても簡単な処理で実装出来るようにしています。
public MarkovKey Push(string key) { var newKeys = new string[N]; newKeys[0] = key; for (int i = 0; i < N - 1; i++) { newKeys[i + 1] = _keys[i]; } return new MarkovKey(newKeys); }
Push メソッドに新しいキーを指定して、次の MarkovKey を作っていくという処理を続けるだけです。
最初はもっとめんどくさいコードでしたが、そこそこコンパクトに出来ました。