溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

php可以實(shí)現(xiàn)推薦算法嗎

發(fā)布時(shí)間:2020-07-03 10:55:57 來(lái)源:億速云 閱讀:284 作者:Leah 欄目:編程語(yǔ)言

php可以實(shí)現(xiàn)推薦算法嗎?針對(duì)這個(gè)問(wèn)題,這篇文章詳細(xì)介紹了相對(duì)應(yīng)的分析和解答,希望可以幫助更多想解決這個(gè)問(wèn)題的小伙伴找到更簡(jiǎn)單易行的方法。

推薦算法是非常古老的,在機(jī)器學(xué)習(xí)還沒(méi)有興起的時(shí)候就有需求和應(yīng)用了。

協(xié)同過(guò)濾(Collaborative Filtering)作為推薦算法中最經(jīng)典的類(lèi)型,包括在線的協(xié)同離線的過(guò)濾兩部分。所謂在線協(xié)同,就是通過(guò)在線數(shù)據(jù)找到用戶可能喜歡的物品,而離線過(guò)濾,則是過(guò)濾掉一些不值得推薦的數(shù)據(jù),比比如推薦值評(píng)分低的數(shù)據(jù),或者雖然推薦值高但是用戶已經(jīng)購(gòu)買(mǎi)的數(shù)據(jù)。

下面就介紹下怎樣用PHP+MySQL實(shí)現(xiàn)簡(jiǎn)單的協(xié)同過(guò)濾算法。

要實(shí)現(xiàn)協(xié)同過(guò)濾推薦算法,首先就要理解算法的核心思想和流程。該算法的核心思想可以概括為:若a,b喜歡同一系列的物品(暫時(shí)稱b是a的鄰居吧),則a很可能喜歡b喜歡的其他物品。算法的實(shí)現(xiàn)流程可以簡(jiǎn)單概括為:1.確定a有哪些鄰居 2.通過(guò)鄰居來(lái)預(yù)測(cè)a可能會(huì)喜歡哪種物品  3.將a可能喜歡的物品推薦給a。

算法核心的公式如下:

1.余弦相似度(求鄰居):

php可以實(shí)現(xiàn)推薦算法嗎

2.預(yù)測(cè)公式(預(yù)測(cè)a可能會(huì)喜歡哪種物品):

php可以實(shí)現(xiàn)推薦算法嗎

僅從這兩個(gè)公式我們就可以看出,僅僅是按照這兩個(gè)公式進(jìn)行計(jì)算,就需要進(jìn)行大量的循環(huán)與判斷,而且還涉及到排序的問(wèn)題,就涉及到排序算法的選擇與使用,這里選快排。

首先建表:

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);

php可以實(shí)現(xiàn)推薦算法嗎

這里只對(duì)最后一行的Leo進(jìn)行推薦,看看f,g,h哪個(gè)可以推薦給他。

用php+mysql,流程圖如下:

php可以實(shí)現(xiàn)推薦算法嗎

連接數(shù)據(jù)庫(kù)并將其存儲(chǔ)為二維數(shù)組的代碼如下:

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[][]是一個(gè)二維數(shù)組
}

問(wèn)題1:這一步完全可以看做是整表查詢,這種查詢是大忌,對(duì)于這種小小的演示系統(tǒng)還可以,但是對(duì)大數(shù)據(jù)的系統(tǒng),沒(méi)有效率。

求Leo與其他人的Cos值代碼如下:

/*
 * 以下示例只求Leo的推薦,如此給變量命名我也是醉了;初次理解算法,先不考慮效率和邏輯的問(wèn)題,主要把過(guò)程做出來(lái)
 */
 
$cos = array();
$cos[0] = 0;
$fm1 = 0;
//開(kāi)始計(jì)算cos
//計(jì)算分母1,分母1是第一個(gè)公式里面 “*”號(hào)左邊的內(nèi)容,分母二是右邊的內(nèi)容
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++){
    //計(jì)算分子
if($array[5][$j] != null && $array[$i][$j] != null){
$fz += $array[5][$j] * $array[$i][$j];
}
//計(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/>";
}

這一步得到的結(jié)果:

php可以實(shí)現(xiàn)推薦算法嗎

將求好的Cos值排序,采用快排代碼如下:

//對(duì)計(jì)算結(jié)果進(jìn)行排序,湊合用快排吧先
function quicksort($str){
if(count($str)<=1) return $str;//如果個(gè)數(shù)不大于一,直接返回
$key=$str[0];//取一個(gè)值,稍后用來(lái)比較;
$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);//進(jìn)行遞歸;
$right_arr=quicksort($right_arr);
return array_merge($left_arr,array($key),$right_arr);//將左中右的值合并成一個(gè)數(shù)組;
}
 
$neighbour = array();//$neighbour只是對(duì)cos值進(jìn)行排序并存儲(chǔ)
$neighbour = quicksort($cos);

這里的$neighbour數(shù)組僅僅存儲(chǔ)了從大到小排序好的Cos值,并沒(méi)有與人聯(lián)系起來(lái)。這個(gè)問(wèn)題還要解決。

選出Cos值最高的3個(gè)人,作為L(zhǎng)eo的鄰居:

//$neighbour_set 存儲(chǔ)最近鄰的人和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];//鄰居對(duì)f的評(píng)分
$neighbour_set[$i][3] = $array[$j][7];//鄰居對(duì)g的評(píng)分
$neighbour_set[$i][4] = $array[$j][8];//鄰居對(duì)h的評(píng)分
}
}
}
print_r($neighbour_set);
echo "<p><br/>";

這一步得到的結(jié)果:

php可以實(shí)現(xiàn)推薦算法嗎這是一個(gè)二維數(shù)組,數(shù)組第一層的下標(biāo)為0,1,2,代表3個(gè)人。第二層下標(biāo)0代表鄰居在數(shù)據(jù)表中的順序,比如Jhon是表中的第0個(gè)人;下標(biāo)1代表Leo和鄰居的Cos值;下標(biāo)2,3,4分別代表鄰居對(duì)f,g,h的評(píng)分。

開(kāi)始進(jìn)行預(yù)測(cè),計(jì)算Predict代碼如下:

分別計(jì)算Leo對(duì)f,g,h的預(yù)測(cè)值。在此有一個(gè)問(wèn)題,就是如果有的鄰居對(duì)f,g,h的評(píng)分為空,那么該如何處理。比如Jhon和Mary對(duì)h的評(píng)分就為空。本能的想到用if判斷一下,如果為空則跳過(guò)這組計(jì)算,不過(guò)這樣處理是否合理,有待考慮。以下代碼并沒(méi)有寫(xiě)出這個(gè)if判斷。

//計(jì)算Leo對(duì)f的評(píng)分
$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";
}
 
//計(jì)算Leo對(duì)g的評(píng)分
$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";
}
 
//計(jì)算Leo對(duì)h的評(píng)分
$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是對(duì)Leo的推薦數(shù)組,其內(nèi)容類(lèi)似如下;
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個(gè)物品推薦給Leo。這段代碼沒(méi)有寫(xiě)。

從上面的示例中可以看出,推薦算法的實(shí)現(xiàn)非常麻煩,需要循環(huán),判斷,合并數(shù)組等等。如果處理不當(dāng),反而會(huì)成為系統(tǒng)的累贅。在實(shí)際處理中還有以下問(wèn)題:

1.以上示例我們只對(duì)Leo進(jìn)行推薦,而且我們已經(jīng)知道Leo沒(méi)有評(píng)價(jià)過(guò)f,g,h物品。如果放到實(shí)際的系統(tǒng)里,對(duì)于每一個(gè)需要進(jìn)行推薦的用戶,都要查詢出他沒(méi)有評(píng)價(jià)過(guò)哪些物品,這又是一部分開(kāi)銷(xiāo)。

2.不應(yīng)當(dāng)進(jìn)行整表查詢,在實(shí)際系統(tǒng)中可以設(shè)定一些標(biāo)準(zhǔn)值。比如:我們求Leo與表中的其他人的Cos值,如果該值大于0.80,則表示可以為鄰居。這樣,當(dāng)我找到10個(gè)鄰居之后,就停止求Cos值,避免整表查詢。對(duì)于推薦物品也可以適當(dāng)采用此方法,比如,我只推薦10個(gè)物品,推薦完后就停止求Predict值。

3.隨著系統(tǒng)的使用,物品也會(huì)發(fā)生變化,今天是fgh,明天沒(méi)準(zhǔn)就是xyz了,當(dāng)物品變化時(shí),需要?jiǎng)討B(tài)的改變數(shù)據(jù)表。

4.可以適當(dāng)引進(jìn)基于內(nèi)容的推薦,來(lái)完善推薦算法。

5.推薦的精確性問(wèn)題,這個(gè)設(shè)置不同的標(biāo)準(zhǔn)值,會(huì)影響精確性。

關(guān)于php可以實(shí)現(xiàn)推薦算法嗎問(wèn)題的解答就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,如果你還有很多疑惑沒(méi)有解開(kāi),可以關(guān)注億速云行業(yè)資訊頻道了解更多相關(guān)知識(shí)。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI