しばやん雑記

Azure とメイドさんが大好きなフリーランスのプログラマーのブログ

マルコフ連鎖を使って文章を自動生成するクラスを C# で書いた

NMeCab で形態素解析が簡単に行えるようになったので、何となくマルコフ連鎖での文章生成を選びました。少し時間かけて C# で実装したので、作成したコードを GitHub に置いておきました。

デフォルトでは MarkovKey クラス内で N = 2 としているので、2 次マルコフ連鎖になります。

マルコフ連鎖については説明を省略したいので、Wikipedia のリンクを貼っておきます。

マルコフ連鎖 - 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 回文章を生成するコードになります。

とても簡単な例ですが、このコードを実行すると以下のように文が出力されます。

f:id:shiba-yan:20150308214416p:plain

AddSentence メソッドで追加した文とは異なるパターンが出力されていることが分かります。

大量に形態素解析した結果を追加していけば、もっとランダムな文章が生成されるはずです。なのでデータソースを用意して、後は前回の NMeCab の結果を使う形になります。

f:id:shiba-yan:20150308223111p:plain

これは自分のツイートを形態素解析した結果を 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 を作っていくという処理を続けるだけです。

最初はもっとめんどくさいコードでしたが、そこそこコンパクトに出来ました。