概述:
因为最近对算法这块进行了学习,所以最近对类似淘宝商品推荐的协同推荐算法进行了整理总结,本文将用php语言进行实现,文章将从以下几点进行终结:
(1)什么是协同推荐算法?有什么用?
(2)依据什么数学方法公式,为什么要用它?
(3)实现流程是怎样的?
(4)具体实现步骤。
该算法的核心思想可以概括为:若a,b喜欢同一系列的物品(暂时称b是a的邻居吧),则a很可能喜欢b喜欢的其他物品。算法的实现流程可以简单概括为:1.确定a有哪些邻居 2.通过邻居来预测a可能会喜欢哪种物品 3.将a可能喜欢的物品推荐给a。
现在我们了解了这个核心思想以后,我们知道算法的核心是数学逻辑,我们必须理解其数学思想,然后再转化为编程思想达到我们的目标:
我们先回忆一下余弦定理:
可见cosA的夹角越小cosA的值越大,则边c和边b的长度越相近,因此我们利用余弦定理的向量方式类推出如下公式:
1.余弦相似度(求邻居):
2.预测公式(预测a可能会喜欢哪种物品):
接下来我们介绍一下实现流程:
现在我们具体看看怎样用php实现这个算法:
(1)数据准备:在这里我们直接定义一组数据
$userarray= [
['name'=>'A','a'=>3,'b'=>2,'c'=>1,'d'=>5,'e'=>null,'f'=>null,'g'=>null],
['name'=>'B','a'=>1,'b'=>6,'c'=>6,'d'=>5,'e'=>2,'f'=>3,'g'=>5],
['name'=>'C','a'=>3,'b'=>5,'c'=>null,'d'=>4,'e'=>3,'f'=>3,'g'=>6],
['name'=>'D','a'=>4,'b'=>1,'c'=>1,'d'=>5,'e'=>3,'f'=>3,'g'=>3],
['name'=>'E','a'=>5,'b'=>1,'c'=>null,'d'=>4,'e'=>5,'f'=>1,'g'=>5],
['name'=>'F','a'=>1,'b'=>3,'c'=>2,'d'=>5,'e'=>6,'f'=>null,'g'=>4],
['name'=>'G','a'=>1,'b'=>5,'c'=>2,'d'=>5,'e'=>2,'f'=>3ll,'g'=>5]
];
(2)我们以A用户为对象分别计算出他们的余弦相似度,然后将其存入数组$cos中:
/*
* 以下示例只求A的推荐
*/
$denominator_left = 0;//分母左边初始值
//开始计算cos
//计算分母左边
for($i=1;$i<8;$i++){
if($userarray[0][$i] != null){//$userarray[0]代表A
$denominator_left += $userarray[0][$i] * $userarray[0][$i];
}
}
$denominator_left = sqrt($denominator_left);//取算数平方根的值
for($i=1;$i<6;$i++){
$numerator = 0;//分子初始值
$denominator_right = 0;//分母右边初始值
for($j=1;$j<8;$j++){
//计算分子
if($userarray[0][$j] != null && $userarray[$i][$j] != null){
$numerator += $userarray[0][$j] * $userarray[$i][$j];
}
//计算分母右边
if($userarray[$i][$j] != null){
$denominator_right += $userarray[$i][$j] * $userarray[$i][$j];
}
}
$denominator_right = sqrt($denominator_right );
$cos[$i]['cos'] = $numerator /$denominator_left /$denominator_right ;//存储当前用户的cos近似值
$cos[$i]['name'] = $userarray[$i]['name'];//存储当前用户的名字
$cos[$i]['e'] = $userarray[$i]['e'];//存储当前用户的e物品评分
$cos[$i]['f'] = $userarray[$i]['f'];//存储当前用户的f物品评分
$cos[$i]['g'] = $userarray[$i]['g'];//存储当前用户的g物品评分
}
(3)我们对余弦近似值进行由大到小的排序,抽取前三个用户作为A用户的邻居,我们使用冒泡排序法对其进行排序
// 第一层可以理解为从数组中键为0开始循环到最后一个
for ($i = 0; $i < count($cos) ; $i++) {
// 第二层为从$i+1的地方循环到数组最后
for ($j = $i+1; $j < count($cos); $j++) {
// 比较数组中两个相邻值的大小
if ($cos[$i]['cos'] < $cos[$j]['cos']) {
$tem = $cos[$i]; // 这里临时变量,存贮$i的值
$cos[$i] = $cos[$j]; // 第一次更换位置
$cos[$j] = $tem; // 完成位置互换
}
}
}
(4)接下来我们对A用户可能喜欢的物品进行预测,利用第二个公式,求出product值
//计算A对e的评分
$numerator= 0;//分子初始值
$denominator= 0;//分母初始值
for($i=0;$i<3;$i++){
$numerator+= $cos[$i]['cos'] * $cos[$i]['e'];
$denominator+= $cos[$i]['cos'];
}
$score_e = $numerator/sqrt($denominator);
//计算A对f的评分
$numerator= 0;//分子初始值
$denominator= 0;//分母初始值
for($i=0;$i<3;$i++){
$numerator+= $cos[$i]['cos'] * $cos[$i]['f'];
$denominator+= $cos[$i]['cos'];
}
$score_f= $numerator/sqrt($denominator);
//计算A对g的评分
$numerator= 0;//分子初始值
$denominator= 0;//分母初始值
for($i=0;$i<3;$i++){
$numerator+= $cos[$i]['cos'] * $cos[$i]['g'];
$denominator+= $cos[$i]['cos'];
}
$score_g= $numerator/sqrt($denominator);
最后我们可以比较这些值,可以选取值最大的物品推荐给用户A