在上面两篇文章已经讲了如何通过用户对产品的评分分别计算出某个用户与其他用户之间的相似度,那么在计算完相似度后如何才能获取和该用户相似度高的人呢,方法分为两种:
1、固定数量的K个邻居,(K-neighborhoods)。意思很明确,就是按分数高低降序取K个
2、基于相似度门槛的邻居,(Threshord-based neighborhood)。取分数K分以上的作为邻居
<?php
/**
* 余玄相似度计算出3个用户的相似度
* 通过7件产品分析用户喜好相似度
* 相似度使用函数 sim(user1,user2) =cos∂
*
* 设A、B为多维矩阵
*
* ∑(Ai•Bi) ∑(Ai•Bi) ∑(USER1_i•USER2_i)
* cos∂ = --------------- = ----------------- = -------------------------
* |Ai|•|Bi| √∑ Ai² • √∑ Bi² √∑ USER1_i² • √∑ USER2_i²
*/
$infoTable = [
'user1' => [
5, 5, 4, 7, 8, 9, 4, // 分别为产品1评分,产品2评分,产品3评分,产品4评分,产品5评分,产品6评分,产品7评分
],
'user2' => [
1, 9, 1, 9, 2, 2, 8,
],
'user3' => [
5, 5, 5, 7, 8, 9, 3,
],
'user4' => [
9, 1, 9, 1, 8, 9, 1,
],
];
function calc($user1, $user2)
{
global $infoTable;
$sumAiBi = 0;
$sumAi = 0;
$sumBi = 0;
$len = 7; //7个产品
for ($i = 0; $i < $len; $i++) {
//∑(Ai•Bi)
$sumAiBi += $infoTable[$user1][$i] * $infoTable[$user2][$i];
//∑USER1_i
$sumAi += pow($infoTable[$user1][$i], 2);
//∑USER2_i
$sumBi += pow($infoTable[$user2][$i], 2);
}
return $sumAiBi / (sqrt($sumAi) * sqrt($sumBi));
}
/**
* K邻居
*
* @param array $arr
* @param int $K
*
* @return array
*/
function kNeighborhoods(array $arr, int $K)
{
// 根据value降序排列
array_multisort($arr, SORT_DESC);
$KN_ARR = [];
$i = 0;
foreach ($arr as $k => $v) {
if ($i >= $K) {
break;
}
$KN_ARR[$k] = $v;
$i++;
}
return $KN_ARR;
}
/**
* 相似度门槛
*
* @param array $arr
* @param float $K
*
* @return array
*/
function thresholdBaseNeighborhoods(array $arr, float $K)
{
$thresholdBashArr = [];
foreach ($arr as $k => $v) {
if ($v >= $K) {
$thresholdBashArr[$k] = $v;
}
}
return $thresholdBashArr;
}
// 计算user1的K邻居
$simArr = [];
$kUser = 'user1';
foreach ($infoTable as $k => $v) {
if ($k == $kUser) {
continue;
}
$simArr[$k] = calc($kUser, $k);
}
print_r($simArr);
echo 'K邻居,K = 2时:' . PHP_EOL;
print_r(kNeighborhoods($simArr, 2));
echo '相似度门槛,K=0.9时:'.PHP_EOL;
print_r(thresholdBaseNeighborhoods($simArr,0.9));