transformPrefsでスコアのディクショナリをアイテムごとのディクショナリに変換して
アイテムごとにループを回して各アイテムに似ているアイテムをランキングでとってくる
各ユーザーの評価で映画のタイトルのスコアに重みづけをしてアイテムベースでユーザーにオススメをする
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function calculateSimilarItems($critics, $n) { | |
$result = array(); | |
$itemPrefs = transformPrefs($critics); | |
$c = 0; | |
foreach($itemPrefs as $item => $v) { | |
$c++; | |
if( $c%100 == 0){ | |
echo sprintf("%d / %d", $c, count($itemPrefs)); | |
} | |
$scores = topMatches($itemPrefs, $item, $n, 'distance'); | |
$result[$item] = $scores; | |
} | |
return $result; | |
} | |
$n = 10; | |
$itemsim = calculateSimilarItems($critics, $n); | |
function getRecommendedItems($critics, $itemMatch, $user) { | |
$userRatings = $critics[$user]; | |
$scores = array(); | |
$totalSim = array(); | |
foreach ($userRatings as $item => $rating) { | |
foreach ($itemMatch[$item] as $item2 => $similarity) { | |
if ( array_key_exists($item2, $userRatings)) { | |
continue; | |
} | |
if( !isset($scores[$item2]) ){ | |
$scores[$item2] = $similarity*$rating; | |
}else{ | |
$scores[$item2] = $scores[$item2] + $similarity*$rating; | |
} | |
if (!isset($totalSim[$item2])) { | |
$totalSim[$item2] = $similarity; | |
} else { | |
$totalSim[$item2] = $totalSim[$item2] + $similarity; | |
} | |
} | |
} | |
foreach ($scores as $item => $score) { | |
$rankings[$item] = $score/$totalSim[$item]; | |
} | |
arsort($rankings); | |
return $rankings; | |
} | |
$recommendation = getRecommendedItems($critics, $itemsim, 'Toby'); | |
var_dump($recommendation); |
まず、loadMovieLens関数でMovieLensのデータをロードします。そして、getRecommendations関数を使ってユーザーベースの推薦を行い、
calculateSimilarItems関数を使ってアイテム間の相関を計算し、getRecommendedItems関数でアイテムベースの推薦を行います。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function loadMovieLens($path) { | |
$movies = array(); | |
$fp = fopen($path . "/u.item", "r"); | |
while($line = fgets($fp)){ | |
$line_explode = explode("|", $line); | |
$movies[$line_explode[0]] = $line_explode[1]; | |
} | |
fclose($fp); | |
$prefs = array(); | |
$fp = fopen($path . "/u.data", "r"); | |
while($line = fgets($fp)){ | |
$data_explode = explode("\t",$line); | |
$user = $data_explode[0]; | |
$movieid = $data_explode[1]; | |
$rating = $data_explode[2]; | |
$ts = $data_explode[3]; | |
if(!isset($prefs[$user])) { | |
$prefs[$user] = array(); | |
} | |
$prefs[$user][$movies[$movieid]]=$rating; | |
} | |
return $prefs; | |
} | |
$lines = loadMovieLens('MovieLensのデータを保存したフォルダ'); | |
$movie_recommend = getRecommendations($lines, '87', 'pearson'); | |
$itemsim = calculateSimilarItems($lines, 50); | |
$movie_recommend_item = getRecommendedItems($lines, $itemsim, '87'); | |
var_dump($itemsim); |
実際にアイテムベースで推薦を行う場合のロジックはどのようなものなのでしょうか?
まず、アイテムベースの推薦で使っている関数は
calculateSimilarItems
transformPrefs
topMatches
sim_peason( or sim_distance)
でやっていることといえば
まず、ユーザーごとの各アイテムの評価のarrayをアイテムごとのユーザーによる評価のarrayに変換しています。
つまり、arrayの第一連想配列のキーはアイテム名で、第二連想配列のキーは評価者となります。
そして、sim_peasonを使ってアイテム間の相関スコアを取得します。
そのアイテムスコアを使ってtopMaches関数で各アイテムごとに、相関スコアが高い順にアイテムをランキング付けします。
たとえば、Superman Returnsに一番相関が高いのはYou Me and Dupreeでスコアは0.657
二番目に高いのはLady in the Waterでスコアは0.487といった具合です。
ここまでで、どのアイテムとどのアイテムが似ているのかがわかるようになったわけです。
最後にユーザーに対して推薦を行う場合は
ユーザーが既に評価した(購入した)アイテムとまだ購入していないアイテムの相関スコアに対して
評価したアイテムの評価で重み付けを行い、まだ購入していないアイテムそれぞれの推薦度スコアを計算します
そして推薦度スコアがもっとも高いものをユーザーに推薦します。
この章では一旦、ユーザーベースの推薦を行ったあとに、そのロジックを逆転させてアイテムベースの推薦を行っているので
どういうロジックでアイテムベースの推薦を行っているのかを理解するのがすこし難しいですね
0 件のコメント:
コメントを投稿