こんにちは、E-Haです。
PHPでTwitterで自動でつぶやいてくれるTwitterBotの作り方を紹介します。
今回は、第5回ということで自動でつぶやきを生成する方法について説明していきます。
目次
タイムラインの収集
タイムラインを集めるには
自分のタイムラインの収集は次のようにします。
<?php require_once ("twitteroauth/twitteroauth.php"); require_once ("developer_info.php"); $oAuth = new TwitterOAuth ( $consumerKey, $consumerSecret, $accessToken, $accessTokenSecret ); // タイムラインを取得する $timeline = $oAuth->get ( 'statuses/home_timeline', array ( 'count' => 100 ) ); //取得してきたタイムラインをフィルタリングする foreach ( $timeline as $i => $tweet ) { if (! preg_match ( "/RT|QT|@|http|&|%/", "$tweet->text" )) { $tweetList [] = trim(mb_convert_kana( $tweet->text, ""s"")) . "\n"; } }
@の入ったつぶやきやURLの入ったつぶやきを拾ってしまうと、スパム扱いを受けることが考えられるので除外する。
もっと良い、フィルタリング方法があると思うが勉強不足。
YahooAPIを使った形態素解析
Yahooの日本語形態素解析APIを使おう
Yahooの日本語形態素解析APIは、文章を投げてあげると形態素解析をかけて返してくれるAPIです。
Yahoo!デベロッパーに登録し、得られたアプリケーションIDを使います。
$appid="自分のアプリケーションID"; $sentence="自分で用意した文章"; $url = "http://jlp.yahooapis.jp/MAService/V1/parse?appid=" . $appid . "&sentence=" . $sentence; $rss = file_get_contents ( $url ); $xml = simplexml_load_string ( $rss );
こうして返ってきた戻り値から必要な値、ここでは単語を抜き出して行きます。
$i = 0; foreach ( $xml->ma_result->word_list->word as $item ) { $word [$i] = $item->surface; $i ++; }
こうして、文章を分かち書きした結果がひとつの配列に格納されました。
分かち書き結果のデータベースへの登録
データベースを使うには
文章を自動生成するための辞書を作成するために、データベースを用意しました。
データベースにPHPからアクセスするには、PDOを使います。
require_once ("db_para.php"); // MySQLへ接続する $sql_ = new PDO ( "mysql:dbname=$db;host=$url", "$user", "$pass" ); $sql_->setAttribute ( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
$url = "データベースのURL"; $user = "ユーザID"; $pass = "パスワード"; $db = "データベース名"; $dbtable="テーブル名";
次に、先ほど用意した配列をデータベースに登録します。
// SQLへの入力 for($j = 0; $j < count ( $word ) - 2; $j ++) { // テーブルのハッシュ値を作成する $hash = md5 ( $word [$j] . $word [$j + 1] . $word [$j + 2] ); $st=$sql_->query("SELECT COUNT(id) FROM $dbtable WHERE id='$hash'"); if ($st->fetchColumn()==0){ // MySQLへデータを挿入する準備 $st = $sql_->prepare ( "INSERT INTO $dbtable VALUES(?,?,?,?)" ); // MySQLへデータを挿入する $st->execute ( array ( $hash, $word [$j], $word [$j + 1], $word [$j + 2] ) ); } }
この時、データベースに登録される組み合わせが重複しないようにするため、ハッシュ値を作成しておきます。
こうすることで、データベースの容量を抑えることができる(はず)です。
マルコフ連鎖による文章作成
マルコフ連鎖とは
分かち書きの結果を登録する時に何気なく3単語区切りで重なりあうように登録していましたが、その理由はマルコフ連鎖にあります。
マルコフ連鎖は、一連の確率変数 X1, X2, X3, … で、現在の状態が決まっていれば、過去および未来の状態は独立であるものである。形式的には、
\Pr(X_{n+1}=x|X_n=x_n, \ldots, X_1=x_1, X_0=x_0) =
\Pr(X_{n+1}=x|X_n=x_n)\,
Xi のとりうる値は、連鎖の状態空間と呼ばれ、可算集合S をなす。マルコフ連鎖は有向グラフで表現され、エッジにはある状態から他の状態へ遷移する確率を表示する。
マルコフ連鎖の一例に有限状態機械がある。これは、時刻n において状態 y にあるとすると、それが時刻n + 1 において状態x に動く確率は、現在の状態にだけ依存し、時刻n には依存しない。
時間的に均一な(斉時的)マルコフ連鎖とは、すべてのn に対し
\Pr(X_{n+1}=x|X_n=y) = \Pr(X_{n}=x|X_{n-1}=y)\,
であるような過程をいう。一般の、時間的に均一でないマルコフ連鎖は、この等式を満たさない。
マルコフ連鎖-Wikipedia
と難しそうなことが書いてありますが、文章を作る際に大切なことは今の単語から次に来る単語は限られているということです。
例えば、
私はトムです。
という文章があった時、分かち書きの結果は
私 は トム です。
となります。
つまり、私と来たら次は、はと来るだろうことが予想されます。
更に言うならば、
私はと来た時、続く単語がブルドーザーとはおおよそならないだろうことが考えられます。
そこで、いくつかの単語から次に来る単語を絞り込むことでそれなりな文章を作ることができるだろうという手法です。
マルコフ連鎖の実装
実際の実装では
// MySQLから最初のキーデータを取得する $st = $sql_->query ( "SELECT * FROM $dbtable where un='[START]'" ); while ( $row = $st->fetch () ) { $key_table [] = array ( $row ['un'], $row ['deux'], $row ['trois'] ); } // 文章を作っていく $key = $key_table [rand ( 0, count ( $key_table ) - 1 )]; $centence = $key [1]; while ( true ) { $st = $sql_->prepare ( "SELECT * FROM $dbtable WHERE un=? AND deux=?" ); $st->bindValue ( 1, $key [1] ); $st->bindValue ( 2, $key [2] ); $st->execute (); $key_table = null; while ( $row = $st->fetch () ) { $key_table [] = array ( $row ['un'], $row ['deux'], $row ['trois'] ); } $st->closeCursor (); $key = $key_table [rand ( 0, count ( $key_table ) - 1 )]; if(strcmp($key[1], '_')!=0){ $centence = $centence . $key [1]; }
文章の始まりとなるキーを呼び出し、その中からランダムに一つのテーブルを選びます。
選ばれたテーブルから次の単語を探しまたランダムに選びというのを繰り返すことで文章ができていきます。
これでは、終わらなくなりうるので文章の終りとなる単語には予め文章の終りとなるキーをつけておくことで文章を終わらせることができます。
以上で、自動で文章を作成することができるようになりました。