work.log

元エンジニアの備忘録的ブログ

Perlでマルコフ連鎖用の辞書を作ってみる

投稿:2013-08-26 17:59  更新:

MeCab で形態要素解析に引き続き、今回は分かち書きした単語を元にマルコフ連鎖というものをやってみたいと思います。

ただ、マルコフ連鎖の仕組みがイマイチ理解できなかったので、今回はマルコフ連鎖とは何かを簡単に調べてみました。

各方面の記事を見ながら解釈すると、マルコフ連鎖とは以下の様なもののようです。

マルコフ連鎖についての解釈

マルコフ連鎖とは、ある事象が起きる確率が直前の事象にのみ依存することを指す。

「A → B → C」という事象が発生した場合、「C」が発生する確率は「B」にのみ依存する。
この場合「C」が起こる確率は、「A → B」「C → B」のようになり、「B → A」のような場合には「C」は発生しない。

Wiki とかを見ると???な感じになってしまいますが、多分こんな感じの解釈でいいと思います。少なくとも今回の目的を達成するにはこういう理解でいいと思ってます。

次に以下の文章に当てはめて考えてみます。

文章:「昨日は晴れ、今日も晴れ。」

連鎖1:「昨日」→「も」→「晴れ」
連鎖2:「今日」→「は」→「晴れ」

「晴れ」という単語は、「も」か「は」の後にのみ出現する。

こういう感じでしょうか。

これを連想配列に入れてマルコフ辞書なるもの作り、キーとなる単語をランダムに選びながら文章を作成していくようです。

ただし 1 単語をキーにしてしまうと、文章とは程遠い物ができやすくなるようなので、2 – 3 単語を 1 つのキーとしてやるのが良いみたいです。

これに基づいて、以下のようなスクリプトでマルコフ辞書を生成してみました。

#!/usr/bin/perl

use strict;
use warnings;
use Text::MeCab;
use Data::Dumper;

    my $str = 'ブログのエントリータイトルを自動作成して候補リストを作成したい!';

    my $mecab = Text::MeCab->new();
    my $node  = $mecab->parse($str);

    my $key1   = '';
    my $key2   = '';
    my $suffix = '';
    my $count  = 0;
    my @word   = ();
    my $markov = {};

    while ($node->surface) {

        push(@word, $node->surface);

        $node = $node->next;
        $count++;

    }

    for (my $i = 0; $i < $count -2; $i++) {

        $key1 = $word[$i];
        $key2 = $word[($i + 1)];
        $suffix  = $word[($i + 2)];

        push(@{$markov->{$key1}->{$key2}}, $suffix);

    } 

    print Dumper($markov);

exit;

連想配列 $markov の中はこんな感じになります。

$VAR1 = {
          'エントリータイトル' => {
                                    'を' => [
                                              '自動作成'
                                            ]
                                  },
          'して' => {
                      '候補リスト' => [
                                        'を'
                                      ]
                    },
          'ブログ' => {
                        'の' => [
                                  'エントリータイトル'
                                ]
                      },
          '候補リスト' => {
                            'を' => [
                                      '作成'
                                    ]
                          },
          'の' => {
                    'エントリータイトル' => [
                                              'を'
                                            ]
                  },
          'を' => {
                    '自動作成' => [
                                    'して'
                                  ],
                    '作成' => [
                                'したい'
                              ]
                  },
          '自動作成' => {
                          'して' => [
                                      '候補リスト'
                                    ]
                        },
          '作成' => {
                      'したい' => [
                                    '!'
                                  ]
                    }
        };

$key1->{$key2} をキーにして、その中の配列に格納された単語を結びつけていけば文章が出来上がるという感じですかね。

ただ、この例では文字数が少ないので 1 単語しか配列に格納されていないです。この場合、同じ文字の繰り返しで終わりそうなので文字量はある程度欲しいみたいですね。

次回は、マルコフ辞書を元にマルコフ連鎖で文章を作る所をやってみたいと思います。