【PHP】Yahoo!の形態素解析

MeCab

ふと形態素解析をやってみたくなりPHPで何かないかと色々探したらMeCabがよさそうだったのでやってみました。解析対象はTwitterの発言です。
PHPMeCabを使える拡張モジュールもありますが使わずに。
ローカルでは動くようになったんですがやはりサーバにあげるとどうも…。
この辺をきちんと理解してないので勉強したいとは思いますがやっぱりサーバにソフトをインストしないといけないのかな?^^;
そうするとあとはYahoo!形態素解析を利用するしか無いかなーとそちらへ移行。

Yahoo!形態素解析

まずアプリケーションIDを取得します。
Yahoo!がサンプルコードを配布してくれています。こんなの
解析オプションが付けられるようになってますが、私はただ解析できればよかったので解析の部分をこのコードを参考に作りました。

とりあえず解析対象がないと何もならないのでTwitterの自分の発言をとってきます。

$user_timeline = "http://api.twitter.com/1/statuses/user_timeline.xml?screen_name=";
$user_timeline .= $screen_name ."&count=" .$size;
//$sizeは取得するツイート数
$file = file_get_contents($user_timeline);
$XML = simplexml_load_string($file);

xml形式で取得してきて

$statusCount = count($XML->status);
for($i=0;$i<$statusCount/2;$i++){
	$status = $XML->status[$i];
	$state = $status->text;
	$state = mb_convert_kana($state,"as",'utf-8');
}
$text .= $state;

取得できたツイート数の前半をまず変数に格納します。
なぜ半分にするかというと、あまり大きいものを解析しようとするとエラーが出るから。
多くても35ツイートくらいがギリギリでした。よって最大解析数は70にしてあります。(解析ツイート数は任意)
後半のツイートも同じ様に格納。
試しつつ調べるとリプライの多い人は多い単語にアカウント名が出てきてしまいました。
また、ハッシュタグの#以降の文字列やURLも入ってしまうのを避けるため(※URLは処理がめんd(ryだったのでURLを含むツイートは入れないようにしました)

for($i=0;$i<$statusCount/2;$i++){	//前半ツイートを取得
	$status = $XML->status[$i];
	$state = $status->text;
	$state = mb_convert_kana($state,"as",'utf-8');
	if(preg_match("/^@/",$state) === 1){
		$idx = strpos($state,' ');
		$state = substr($state,$idx + 1);	//空白以降の文字列を取得
	}
	if(preg_match("/#/",$state) === 1){
		$idx = strpos($state,'#');
		$state = substr($state,0,$idx-1);
	}
	if(preg_match("/http/",$state) === 0){
		$text .= $state;
	}
}

最終的にはこんな感じ。(ハッシュタグのあたりはいい加減です^p^;)
$textに解析にかけたい文章が入ったので、解析します。

$url = "http://jlp.yahooapis.jp/MAService/V1/parse?appid=".$appid."&results=ma&filter=9";
$url .= "&sentence=".urlencode($text);
$xml = simplexml_load_file($url);
foreach ($xml->ma_result->word_list->word as $cur){
	$data .= $cur->surface ." ";
}

解析にかけるためのURLは

http://jlp.yahooapis.jp/MAService/V1/parse?appid=<取得したアプリID>&results=<maもしくはuniq>&sentence=<解析したい文字列>

です。ここに色々説明があります。
appidと、results、sentenceは絶対にURLに入れないといけなくてパラメータを=のあとに書け
ということ、です。(最初これを理解するに時間かかった…)
appidは取得したIDを入れればいいです。(長いので変数に格納してあります)
sentenceは解析したい文字列なのでここでは$textです。
filterは必須ではありませんが、名詞のみ欲しかったので9(名詞)を指定。
resultですがリクエストしてみれば分かりますが、maは品詞や読み方、uniqはその形態素が何回出てきたかの情報を持ってきます。
よってmaを指定すると同じ単語も何回も出てきて、uniqを指定すると同じ単語はまとめられるので1回しか出てきませんが、その単語が何回出てきたかの数字を持ってきます。
つまり「すもももももももものうち」という文字列を解析したら、maは「もも」が2回出てきて、uniqなら「もも」は1回しか表示されませんが2回出てきたよ、という情報を持ってきてくれます。
maの場合uniqの場合

よって、まずmaで前半ツイートを解析します。
得られたデータから$dataという変数に単語($xml->ma_result->word_list->word->surface)を格納していきます。

foreach ($xml->ma_result->word_list->word as $cur){
	$data .= $cur->surface ." ";
}

実際は調整するために様々な条件(数字のみの名詞は無視・「ww」は無視)を入れています。

後半ツイートも同じです(なんて無駄の多い…)
$dataに全ツイートの名詞だけを格納することができたので、今度はuniqにして何回同じ単語が出てきたか調べます。

$url = "http://jlp.yahooapis.jp/MAService/V1/parse?appid=".$appid."&results=uniq&uniq_filter=9";
$url .= "&sentence=".urlencode($data);
$xml = simplexml_load_file($url);
foreach ($xml->uniq_result->word_list as $cur){
	for($i=0;$i<10;$i++){
		$tango[$i] = $cur->word[$i]->surface;
		$count[$i] = $cur->word[$i]->count;
	}
}

どうやらでソートしてくれているようなので、出現頻度の高い順にランキングを作りたかった私にとても便利!ということでfor文を使って1から10番目までの単語を取得しました。
最初からuniqだけで解析にかければいいじゃないかと言われそうですが、出来るだけ解析するツイートの数を増やしたかったのと、増やすとuniqを2回やることになりソートがしにくいからです。

あとは結果を表示するだけです。完成したものはこちら
もっと効率のいい書き方があると思いますが動いたのでよし。