oitake blog

いろいろリンク

おすすめリンク

最近のエントリー

カテゴリー

20101012:コメントとトラックバックを停止したことにより、このサイトはアーカイブとなりました。以降、ご連絡はみもねるのウェブサイトへお願いします。
20100703:新ナマコメ(ナマコメ 2)を公開しました。コメントビューア付きで送信面においてもパワーアップしています。
旧ナマコメは将来的に使用できなくする予定なので、可能な限り新ナマコメをお使いください。
20091127:oitake は みもねる になりました。当ブログは無期限更新停止となります。詳細は最新の記事をご覧ください。

スポンサーサイト

一定期間更新がないため広告を表示しています


2009.12.16 Wednesday | | - | - | -

分かち書きとマルコフ連鎖でカオスな文章を生成するまで

(間が空いてしまった上にネタが違うのは仕事のせいです…ぐすん)

分かち書きとマルコフ連鎖というアルゴリズムを組み合わせると、ある文章をバラバラに分解してからメチャクチャに再構築してカオスな文章を生成できるようです。
長門有希さんのセリフをサンプルにして試してみましょう。

生み出されてから3年間、私はずっとそうやって過ごしてきた。
この3年間は特別な不確定要素がなく、いたって平穏。
でも最近になって無視出来ないイレギュラー因子が涼宮ハルヒの周囲に現れた。
それが、あなた。

これを先ほどのロジックで処理してみると、次のような文章が生成されます。生成結果は不定です。

生み出されて平穏。
生み出されて過ごしてから3年間、あなた。
でも最近になって無視出来ないイレギュラー因子がなく、私はずっとそうやって過ごして平穏。
この3年間は特別な不確定要素が、あなた。この3年間、あなた。

長門さん、普通にコクっちゃってますね…。

今回はこのような文章を生成するまでの一貫した手順をご紹介します。
※マルコフ連鎖に関しては、らんたそ氏のブログ「あたまがうにになる」で勉強させていただきました。続きに掲載しているコードも、マルコフ連鎖部分は9割方ソースのままです。

まず分かち書きですが、MeCabかkakasiを使用します(ChaSenは導入に手間がかかるので割愛)。
どちらかをローカル環境にインストールしてください。サンプルコードではMeCabを使用しているので、MeCabの方が簡単です。なお、ここでは実行環境にWindowsを想定しています。

MeCabのインストール手順は下記の通り。

1.MeCabの公式HPにアクセス。
2.「ダウンロード」をクリック。
3.「Binary package for MS-Windows」の「ダウンロード」をクリック。
4.「mecab-win32」の「Download」をクリック。
5.ページ下部の「mecab-X.X.exe」をダウンロード。
6.ダウンロードファイルを実行してインストール。
※フォルダ名を「mecab」としてCドライブ直下に生成してください。

kakasiのインストール手順は下記の通り。

1.kakasiの公式HPにアクセス。
2.「Win32用 バイナリパッケージ」の「Web」をクリック。
3.「kakasi-X.X.X.zip」をダウンロード。
4.ダウンロードファイルを解凍。
5.フォルダ名を「kakasi」としてCドライブ直下に移動。

次に.phpファイルを用意します。
名前は任意です。中身は続きに掲載しているサンプルコードを貼り付けてください。文字コードと改行コードはUTF-8とCR+LFを想定しています。

以上の用意が整ったら、.phpファイルを実行してください。
正常に動作すれば、ローカルに「result.txt」が生成され、自動的にテキストエディタで表示されるはずです。

<?php

// ================================================================
// マルコフ連鎖でカオスな文章生成プログラム (C) 20071217 oitake
// ================================================================

// ================================
// ユーザー定義変数
// ================================

// 分かち書きツールのパス
// ※Cドライブ直下に「mecab」フォルダがあると想定
// ※kakasiを使用する場合は「/kakasi/bin/kakasi.exe -w」
$wakachi_tool='/mecab/bin/mecab.exe -O wakati';

// 最大単語数
$wakachi_tango_num=512;

// 分かち書きの対象となる文字列
$text=<<<EOD
これはテストです。
この文章はマルコフ連鎖のための例文です。内容に意味はありません。
文章が短すぎると連鎖できませんが、逆に長すぎると面白い文章は生成されないでしょう。適度な量の文章を入力してください。

EOD;

// ================================
// 主要処理
// ================================

// 文字コードの検出順序を設定
// ※mb_detect_encodingのために使用
mb_detect_order('ASCII,JIS,UTF-8,EUC-JP,SJIS');

// 対象文字列から改行コードを削除
// ※MeCabの解析は改行コードで停止するため
$text=preg_replace("/(?:¥r¥n|¥r|¥n)/",'',$text);

// 対象文字列の文字コードを変更
// ※kakasiも(初期設定のままであれば)Shift_JISであること
$text=encode($text,'SJIS');

// 対象文字列を分かち書き
$wakachi_string=`echo {$text} | {$wakachi_tool}`;

// 分かち書き文字列の文字コードを変更
$wakachi_string=encode($wakachi_string,'UTF-8');

// 句点の数を取得
// ※長すぎる文字列を生成させないため
$kuten_max=substr_count($wakachi_string,'。');

// 分かち書き文字列を単語ごとに分割
$wakachis=explode(' ',$wakachi_string);

// 単語配列の末尾に番兵を設置
$wakachis[]="¥n";

// 単語がn個以上あるか否か
if(count($wakachis)>2)
{
    $pre=null;
    $head=array();
    $markov=array();

    // マルコフ連鎖用テーブルを作成
    foreach($wakachis as $wakachi)
    {
        if($pre===null)
        {
            $pre=$wakachi;
            $head[]=$wakachi;
        }
        else
        {
            $markov[$pre][]=$wakachi;
            $pre=$wakachi;
        }
    }

    // 文頭を取得
    $result=$pre=$head[array_rand($head)];

    // 文字列を生成
    $kuten_num=0;
    for($i=0 ; $i<$wakachi_tango_num; $i++)
    {
        $pre=$markov[$pre][array_rand($markov[$pre])];
        if($pre==="¥n")
        {
            break;
        }
        $result.=$pre;

        // 句点の数を確認
        if($pre==='。')
        {
            $kuten_num++;
            if($kuten_num===$kuten_max)
            {
                break;
            }
        }

    }

    // 生成文字列を保存
    file_write('result.txt','wb',$result);
    `result.txt`;

}
else
{

    // 単語がn個以下の時
    print '文章が短すぎてマルコフ連鎖を行えません。';

}

// ================================
// 共有関数
// ================================

// 文字コードを変換する
// 第1引数:文字列
// 第2引数:変換後の文字コード
// 返り値 :文字コードを変換された文字列
// ※mb_detect_orderを実行しておくこと。
function encode($buffer,$encoding_new)
{
    $encoding_old=mb_detect_encoding($buffer);
    if($encoding_new!==$encoding_old)
    {
        $buffer=mb_convert_encoding($buffer,$encoding_new,$encoding_old);
    }
    return $buffer;
}

// ファイルに書き込む
// 第1引数:ファイルパス
// 第2引数:ファイルモード
//      ※通常「wb」。
// 第3引数:データ
// 返り値 :true/false
function file_write($path,$mode,$buffer)
{
    $f=fopen($path,$mode);
    if($f!==false)
    {
        if(flock($f,LOCK_EX)!==false)
        {
            if(fwrite($f,$buffer)!==false)
            {
                flock($f,LOCK_UN);
                fclose($f);
                return true;
            }
            flock($f,LOCK_UN);
        }
        fclose($f);
    }
    return false;
}

?>

人工無能にも使われているらしいですよ。あと、自動的に生成されるアフィリエイトブログにも…。
2007.12.17 Monday | 18:55 | その他 | comments(0) | trackbacks(0)

スポンサーサイト


2009.12.16 Wednesday | 18:55 | - | - | -