在計算用戶相似度的過程中,首先對於兩個用戶共同打分過的所有條目,計算他們對於每個條目的評分差值,對差值求平方、求和,再對結果求平方根,這樣得到的值稱爲歐氏距離,但這並不足以作爲顯示度計算的度量值。相似度與距離的概念在某種程度上說是互反的,就其意義而言,歐氏距離越小,兩個用戶相似度就越大。相似度與距離這種反序關係很容易就可以調整過來,比如只要第一顯示度爲歐氏距離加1,再取倒數。
02data.php
<?php
$data = array(
'Frank'=>array(
'Tears'=>5,
'La'=>4,
'Robinson'=>5,
'Yesterday'=>4,
'Wizard'=>5,
'Mozart'=>5,
'Bethoven'=>5
),
'Constantine'=>array(
'Tears'=>5,
'Fiddler'=>5,
'Robinson'=>5,
'Wonderful World'=>4,
'Wizard'=>4,
'Let It Be'=>5,
'Mozart'=>5
),
'Catherine'=>array(
'Tears'=>1,
'Robinson'=>2,
'Yesterday'=>2,
'Beethoven'=>3,
'Sunnday'=>1,
'Let It Be'=>2,
),
'David'=>array(
'Tears'=>1,
'Robinson'=>2,
'Yesterday'=>2,
'Let It Be'=>2,
'Bethoven'=>5
)
);
?>
getSimilarity.php
<?php
class getSimilarity
{
/*
* 獲取兩個用戶共同條目
*/
private function getCommonItems($user1,$user2)
{
$commonItems = 0;
$sim = 0;
foreach ($user1 as $key1=>$value1){
if(isset($user2[$key1])){
$commonItems++;
$sim+=pow($value1-$user2[$key1], 2);
}
}
return array($commonItems, $sim);
}
/*
* 計算相似度
*/
public function getSim($user1,$user2)
{
$cs = $this->getCommonItems($user1, $user2);
if($cs[0]>0){
$sim = sqrt($cs[1]/(double)$cs[0]);
$sim = 1 - tanh($sim);
$maxCommonItems = min(count($user1),count($user2));
$sim = $sim*((double)$cs[0]/(double)$maxCommonItems);
return $sim;
}else{
return 0;
}
}
}
include_once '02data.php';
$user1 = $data['Frank'];
$user2 = $data['Constantine'];
$user3 = $data['Catherine'];
$user4 = $data['David'];
$similarity = new getSimilarity();
echo $similarity->getSim($user1,$user2);
echo '<br />';
echo $similarity->getSim($user1,$user3);
echo '<br />';
echo $similarity->getSim($user1,$user4);
echo '<br />';
echo $similarity->getSim($user2,$user3);
echo '<br />';
echo $similarity->getSim($user2,$user4);
echo '<br />';
echo $similarity->getSim($user3,$user4);
?>
上面的代碼先求出兩個用戶有一些共同評分的歌曲,那麼把他們對其中每首歌曲評分差值的平方和除以這部分歌曲的數量,再對商取平方根,最後用1減去這個雙切正切函數的返回值,最後還考慮的兩個用戶共有的條目的量與兩個人所有可能共有條目量的比率。