类别:PHP问题 / 日期:2019-11-26 / 浏览:173 / 评论:0
php用不了引荐算法吗?
引荐算法是异常陈旧的,在机械进修还没有鼓起的时刻就有需乞降应用了。
协同过滤(Collaborative Filtering)作为引荐算法中最典范的范例,包含在线的协同和离线的过滤两部分。所谓在线协同,就是经由历程在线数据找到用户能够喜好的物品,而离线过滤,则是过滤掉一些不值得引荐的数据,比比方引荐值评分低的数据,或许虽然引荐值高然则用户已购置的数据。
下面就引见下怎样用PHP+MySQL完成简朴的协同过滤算法。
要完成协同过滤引荐算法,起首就要明白算法的中心头脑和流程。该算法的中心头脑能够归纳综合为:若a,b喜好统一系列的物品(临时称b是a的邻人吧),则a极能够喜好b喜好的其他物品。算法的完成流程能够简朴归纳综合为:1.肯定a有哪些邻人 2.经由历程邻人来展望a能够会喜好哪一种物品 3.将a能够喜好的物品引荐给a。
算法中心的公式以下:
1.余弦相似度(求邻人):
2.展望公式(展望a能够会喜好哪一种物品):
仅从这两个公式我们就能够看出,仅仅是根据这两个公式举行盘算,就须要举行大批的轮回与推断,而且还涉及到排序的题目,就涉及到排序算法的挑选与运用,这里选快排。
起首建表:
DROP TABLE IF EXISTS `tb_xttj`; CREATE TABLE `tb_xttj` ( `name` varchar(255) NOT NULL, `a` int(255) default NULL, `b` int(255) default NULL, `c` int(255) default NULL, `d` int(255) default NULL, `e` int(255) default NULL, `f` int(255) default NULL, `g` int(255) default NULL, `h` int(255) default NULL, PRIMARY KEY (`name`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; INSERT INTO `tb_xttj` VALUES ('John', '4', '4', '5', '4', '3', '2', '1', null); INSERT INTO `tb_xttj` VALUES ('Mary', '3', '4', '4', '2', '5', '4', '3', null); INSERT INTO `tb_xttj` VALUES ('Lucy', '2', '3', null, '3', null, '3', '4', '5'); INSERT INTO `tb_xttj` VALUES ('Tom', '3', '4', '5', null, '1', '3', '5', '4'); INSERT INTO `tb_xttj` VALUES ('Bill', '3', '2', '1', '5', '3', '2', '1', '1'); INSERT INTO `tb_xttj` VALUES ('Leo', '3', '4', '5', '2', '4', null, null, null);
这里只对末了一行的Leo举行引荐,看看f,g,h哪一个能够引荐给他。
用php+mysql,流程图以下:
衔接数据库并将其存储为二维数组的代码以下:
header("Content-Type:text/html;charset=utf-8"); mysql_connect("localhost","root","admin"); mysql_select_db("geodatabase"); mysql_query("set names 'utf8'"); $sql = "SELECT * FROM tb_xttj"; $result = mysql_query($sql); $array = array(); while($row=mysql_fetch_array($result)) { $array[]=$row;//$array[][]是一个二维数组 }
题目1:这一步完全能够看作是整表查询,这类查询是大忌,关于这类小小的演示体系还能够,然则对大数据的体系,没有效力。
求Leo与其别人的Cos值代码以下:
/* * 以下示例只求Leo的引荐,云云给变量定名我也是醉了;首次明白算法,先不斟酌效力和逻辑的题目,主要把历程做出来 */ $cos = array(); $cos[0] = 0; $fm1 = 0; //最先盘算cos //盘算分母1,分母1是第一个公式内里 “*”号左侧的内容,分母二是右侧的内容 for($i=1;$i<9;$i++){ if($array[5][$i] != null){//$array[5]代表Leo $fm1 += $array[5][$i] * $array[5][$i]; } } $fm1 = sqrt($fm1); for($i=0;$i<5;$i++){ $fz = 0; $fm2 = 0; echo "Cos(".$array[5][0].",".$array[$i][0].")="; for($j=1;$j<9;$j++){ //盘算份子 if($array[5][$j] != null && $array[$i][$j] != null){ $fz += $array[5][$j] * $array[$i][$j]; } //盘算分母2 if($array[$i][$j] != null){ $fm2 += $array[$i][$j] * $array[$i][$j]; } } $fm2 = sqrt($fm2); $cos[$i] = $fz/$fm1/$fm2; echo $cos[$i]."<br/>"; }
这一步获得的效果:
将求好的Cos值排序,采纳快排代码以下:
//对盘算效果举行排序,凑合用快排吧先 function quicksort($str){ if(count($str)<=1) return $str;//假如个数不大于一,直接返回 $key=$str[0];//取一个值,稍后用来比较; $left_arr=array(); $right_arr=array(); for($i=1;$i<count($str);$i++){//比$key大的放在右侧,小的放在左侧; if($str[$i]>=$key) $left_arr[]=$str[$i]; else $right_arr[]=$str[$i]; } $left_arr=quicksort($left_arr);//举行递归; $right_arr=quicksort($right_arr); return array_merge($left_arr,array($key),$right_arr);//将左中右的值兼并成一个数组; } $neighbour = array();//$neighbour只是对cos值举行排序并存储 $neighbour = quicksort($cos);
这里的$neighbour数组仅仅存储了从大到小排序好的Cos值,并没有与人联系起来。这个题目还要处置惩罚。
选出Cos值最高的3个人,作为Leo的邻人:
//$neighbour_set 存储最近邻的人和cos值 $neighbour_set = array(); for($i=0;$i<3;$i++){ for($j=0;$j<5;$j++){ if($neighbour[$i] == $cos[$j]){ $neighbour_set[$i][0] = $j; $neighbour_set[$i][1] = $cos[$j]; $neighbour_set[$i][2] = $array[$j][6];//邻人对f的评分 $neighbour_set[$i][3] = $array[$j][7];//邻人对g的评分 $neighbour_set[$i][4] = $array[$j][8];//邻人对h的评分 } } } print_r($neighbour_set); echo "<p><br/>";
这一步获得的效果:
这是一个二维数组,数组第一层的下标为0,1,2,代表3个人。第二层下标0代表邻人在数据表中的递次,比方Jhon是表中的第0个人;下标1代表Leo和邻人的Cos值;下标2,3,4离别代表邻人对f,g,h的评分。
最先举行展望,盘算Predict代码以下:
离别盘算Leo对f,g,h的展望值。在此有一个题目,就是假如有的邻人对f,g,h的评分为空,那末该怎样处置惩罚。比方Jhon和Mary对h的评分就为空。天性的想到用if推断一下,假如为空则跳过这组盘算,不过如许处置惩罚是不是合理,有待斟酌。以下代码并没有写出这个if推断。
//盘算Leo对f的评分 $p_arr = array(); $pfz_f = 0; $pfm_f = 0; for($i=0;$i<3;$i++){ $pfz_f += $neighbour_set[$i][1] * $neighbour_set[$i][2]; $pfm_f += $neighbour_set[$i][1]; } $p_arr[0][0] = 6; $p_arr[0][1] = $pfz_f/sqrt($pfm_f); if($p_arr[0][1]>3){ echo "引荐f"; } //盘算Leo对g的评分 $pfz_g = 0; $pfm_g = 0; for($i=0;$i<3;$i++){ $pfz_g += $neighbour_set[$i][1] * $neighbour_set[$i][3]; $pfm_g += $neighbour_set[$i][1]; $p_arr[1][0] = 7; $p_arr[1][1] = $pfz_g/sqrt($pfm_g); } if($p_arr[0][1]>3){ echo "引荐g"; } //盘算Leo对h的评分 $pfz_h = 0; $pfm_h = 0; for($i=0;$i<3;$i++){ $pfz_h += $neighbour_set[$i][1] * $neighbour_set[$i][4]; $pfm_h += $neighbour_set[$i][1]; $p_arr[2][0] = 8; $p_arr[2][1] = $pfz_h/sqrt($pfm_h); } print_r($p_arr); if($p_arr[0][1]>3){ echo "引荐h"; } $p_arr是对Leo的引荐数组,其内容相似以下;
Array ( [0] => Array ( [0] => 6 [1] => 4.2314002228795 ) [1] => Array ( [0] => 7 [1] => 2.6511380196197 ) [2] => Array ( [0] => 8 [1] => 0.45287424581774 ) )
f是第6列,Predict值是4.23,g是第七列,Predict值是2.65........
求完了f,g,h的Predict值后有两种处置惩罚方式:一种是将Predict值大于3的物品引荐给Leo,另一种是将Predict值从大到小排序,将Predict值大的前2个物品引荐给Leo。这段代码没有写。
从上面的示例中能够看出,引荐算法的完成异常贫苦,须要轮回,推断,兼并数组等等。假如处置惩罚不当,反而会成为体系的累坠。在现实处置惩罚中另有以下题目:
1.以上示例我们只对Leo举行引荐,而且我们已晓得Leo没有评价过f,g,h物品。假如放到现实的体系里,关于每个须要举行引荐的用户,都要查询出他没有评价过哪些物品,这又是一部分开支。
2.不应该举行整表查询,在现实体系中能够设定一些规范值。比方:我们求Leo与表中的其别人的Cos值,假如该值大于0.80,则示意能够为邻人。如许,当我找到10个邻人以后,就住手求Cos值,防止整表查询。关于引荐物品也能够恰当采纳此要领,比方,我只引荐10个物品,引荐完后就住手求Predict值。
3.跟着体系的运用,物品也会发生变化,今天是fgh,来日诰日没准就是xyz了,当物品变化时,须要动态的转变数据表。
4.能够恰当引进基于内容的引荐,来完美引荐算法。
5.引荐的准确性题目,这个设置差别的规范值,会影响准确性。
更多PHP相干学问,请接见ki4网!
以上就是php用不了引荐算法吗的细致内容,更多请关注ki4网别的相干文章!