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相干常识,请拜访PHP中文网!
以上就是php用没有了保举算法吗的具体内容,更多请存眷资源魔其它相干文章!
标签: php php教程 php故障解决 php使用问题 推荐算法
抱歉,评论功能暂时关闭!