シンプソン係数を取得するスクリプトを作ってみた

Yahoo! ウェブ検索 API で単語同士の近さを総当たりで調べるの記事を読んで興味が沸いたので、PHPを使って単語同士の近さを調べるためのシンプソン係数を取得するスクリプトを作ってみた。

このシンプソン係数の値が大きいほど、一般的には両方のキーワードの相関関係が強いと推定されるみたい。

たまたまPHPのマニュアルを見ていると、Standard PHP Library(SPL)というライブラリの存在を知ったので、この機会に利用してみることにしてみました。PHP5では標準でSPLが組み込まれているので、活用していこっと。

よく考えたら、PHPをまた使い始めたのはいいんだけど、知識がPHP4のままで古いから、情報収集して知識を更新しておいた方がよさそうだな。

あとはここら辺の関数を使ってみた。

とりあえずこんな感じ。結構コード長くなったなぁ。

<?php

class cURL {
	private $opts = array(
		CURLOPT_HEADER => false, 
		CURLOPT_RETURNTRANSFER => true
	);
	
	public function get($url = "", $data = array(), $myOpts = array()) {
		$params = array();
		foreach ($data as $key => $value) {
			array_push($params, $key . "=" . rawurldecode($value));
		}
		$ch = curl_init($url . "?" . implode("&", $params));
		return $this->exec($ch, $myOpts);
	}
	
	public function post($url = "", $data = array(), $myOpts = array()) {
		$myOpts[CURLOPT_POST] = true;
		$myOpts[CURLOPT_POSTFIELDS] = $data;
		$ch = curl_init($url);
		return $this->exec($ch, $myOpts);
	}
	
	private function exec($ch, $myOpts) {
		// array_mergeでは、配列の添字(数字)が振り直されるので、使わない
		foreach ($myOpts as $key => $value) {
			$this->opts[$key] = $value;
		}
		curl_setopt_array($ch, $this->opts);
		$result = array(
			'code' => curl_getinfo($ch, CURLINFO_HTTP_CODE),
			'cr' => curl_exec($ch),
			'ce' => curl_errno($ch)
		);
		curl_close($ch);
		return $result;
	}
}

function getDataByFile($file = null) {
	if (is_null($file)) {
		throw new Exception("Required data file!");
	}
	$fileObj = new SplFileObject($file);
	if ($fileObj->isReadable()) {
		$data = array();
		while (!$fileObj->eof()) {
			array_push($data, trim($fileObj->fgets()));
			$fileObj->next();
		}
		return $data;
	}
	throw new Exception("Not found data!");
}

function getTotalResults($query = null) {
	if (is_null($query)) {
		throw new Exception("Not found query!");
	}
	$cURL = new cURL();
	$result = $cURL->get(
		"http://search.yahooapis.jp/WebSearchService/V1/webSearch", 
		array(
			"appid" => YAHOO_APP_ID,
			"query" => $query,
			"results" => "1" // 取得する情報は最小限で
		)
	);
	$xml = new SimpleXMLElement($result['cr']);
	return (Integer) $xml{'totalResultsAvailable'};
}

function format($results = array()) {
	$idx = 1;
	foreach ($results as $key => $value) {
		printf("%2d: %.20f %s\n", $idx, $value, $key);
		$idx++;
	}
}

define('YAHOO_APP_ID', '**** Yahoo! AppID ****');
define('TARGET_DATA_FILE', 'people.txt');

// メイン処理
try {
	$data = getDataByFile(TARGET_DATA_FILE);
	$results = array();
	$cache = array();
	foreach ($data as $one) {
		foreach ($data as $other) {
			if ($one == $other) {
				continue;
			}
			if (array_key_exists($other . "-" . $one, $results)) {
				continue;
			}
			
			if (!array_key_exists($one, $cache)) {
				$cache[$one] = getTotalResults($one);
			}
			if (!array_key_exists($other, $cache)) {
				$cache[$other] = getTotalResults($other);
			}
			$oneValue = $cache[$one];
			$otherValue = $cache[$other];
			
			$min = (($oneValue < $otherValue) ? $oneValue : $otherValue);
			$results[$one . "-" . $other] = (getTotalResults($one . "+" . $other)/ $min);
		}		
	}
	if (!arsort($results, SORT_NUMERIC)) {
		throw new Exception("Failed to sort!");
	}
	format($results);
} catch (Exception $ex) {
	print_r($ex);
}

?>

実際に利用したデータ(people.txt)は、適当に選んだ俳優/女優のリストで以下の通りです。

妻夫木聡
永作博美
豊川悦司
松雪泰子
椎名桔平
竹内結子
阿部寛
小栗旬
倍賞美津子
浅野忠信
玉山鉄二
玉木宏 		
織田裕二
蒼井優
宮崎あおい

実行結果は、以下の通り。うーん、これだけだとなんとも言えないなぁ。確かに映画/ドラマで共演したとか仲のよい組み合わせ(宮崎あおい蒼井優とか)が相関関係が高いので、それなりにいい感じなのかも。

$ php simp.php 
 1: 0.27476038338658148596 妻夫木聡-阿部寛
 2: 0.25972850678733033769 阿部寛-玉山鉄二
 3: 0.25188284518828452097 松雪泰子-椎名桔平
 4: 0.23922114047287898475 蒼井優-宮崎あおい
 5: 0.21199999999999999400 妻夫木聡-豊川悦司
 6: 0.21097770154373929330 竹内結子-宮崎あおい
 7: 0.20497737556561085315 妻夫木聡-玉山鉄二
 8: 0.19411764705882353366 小栗旬-玉山鉄二
 9: 0.19131614654002712661 織田裕二-宮崎あおい
10: 0.18914027149321266386 玉山鉄二-玉木宏
11: 0.18782051282051281937 永作博美-蒼井優
12: 0.18702928870292886976 椎名桔平-阿部寛
13: 0.18233333333333331949 豊川悦司-蒼井優
14: 0.17866108786610879200 妻夫木聡-椎名桔平
15: 0.17724358974358975227 永作博美-宮崎あおい
16: 0.17511312217194568985 竹内結子-玉山鉄二
17: 0.17155425219941347614 小栗旬-玉木宏
18: 0.17113402061855670366 妻夫木聡-浅野忠信
19: 0.16877828054298643634 玉山鉄二-宮崎あおい
20: 0.16872852233676977063 小栗旬-浅野忠信

(以下、省略)