此算法主要用來推薦的.
//找出ui,uj兩個用戶同時打過分的課程集合
function getPSet($uid, $ujd)
{
//"select 課程編號 from 評分 where 用戶編號=@ui and 課程編號 in (select 課程編號 from 評分 where 用戶編號=@uj)";
$db=M('videoscore');
$result=$db->where(array('uid'=>$ujd))->field('tid')->select();
//將二維數組 轉爲一位數組 並將字符串轉化爲intval
foreach($result as $k=>$v){
$result[$k]=intval($v['tid']) ;
}
$map['tid']=array('in',$result);
$result=$db->where($map)->distinct(true)->Field('tid')->select();
foreach($result as $k=>$v){
$result[$k]=intval($v['tid']);
}
return $result;
}
//取用戶ui對課程pj第k個評價指標的評分,k=1,2,3分別表示 才藝滿意度、看滿意度、信譽度
function getPScore($ui, $pj, $k)
{
$db=M('videoscore');
$where=array(
'uid'=>$ui,
'tid'=>$pj,
);
//"select AVG(CAST(才藝滿意度 AS decimal(10, 5))) from 用戶_課程評分 where 用戶編號=@ui and 課程編號=@pj group by 用戶編號,課程編號";//求平均,因同一用戶對同一課程可評多次
$result=$db->where($where)->group('tid','uid')->avg('skill');
if($k==2){
$result=$db->where($where)->group('tid','uid')->avg('effects');
}
if($k==3){
$result=$db->where($where)->group('tid','uid')->avg('expression');
}
if($result){
return $result;
}
}
計算用戶相似度 :這裏用的是餘弦相似度算法計算的. (還可以用 皮爾森相關係數法 公式可以google. 方法和餘弦相似度算法類似)
//計算ui,uj兩個用戶 的相似度,按第k個評分指標計算
//餘弦相似度公式
//https://blog.csdn.net/zz_dd_yy/article/details/51926305
function sim($ui, $uj,$k)
{
$samecourse=getPSet($ui,$uj);//找出ui,uj兩個用戶同時打過分的課程集合
foreach($samecourse as $key=>$v){//ui,uj用戶對每一門課程的第$k個指標
$r1=getPScore($ui,$v,$k);
$r2=getPScore($uj,$v,$k);
$sum0+=$r1*$r2;
$sum1+=$r1*$r1;
$sum2+=$r2*$r2;
}
$result=$sum0/(sqrt($sum1)*sqrt($sum2));
return $result;
}
//取除了ui外的所有用戶(評分表中作過評價的用戶)
function getAll_U_ExceptUi($ui)
{
$db=M('videoscore');
$map['uid']=array('NEQ',$ui);
//"select distinct 用戶編號 from 用戶_課程評分 where 用戶編號<>@ui";
$result=$db->where($map)->distinct(true)->select();
foreach($result as $key=>$v){
$result[$key]=intval($v['uid']);//用intval把string轉化爲int
};
$result=array_unique($result);//去掉重複id
foreach($result as $key=>$v){
$copy[]=$v;
}
$result=$copy;
// echo dump($result); die;
return $result;
}
//計算其它用戶與用戶ui的相似度,按第k個評分指標計算 similar相似度 uid1 用戶1 uid2 用戶2
function computeSimToUi($ui,$k)
{
$dtU = getAll_U_ExceptUi($ui);//取除了ui外的所有用戶
// $dtSim = array(array("用戶編號1","用戶編號2","相似度"));//存放相似度的表
for ($i = 0; $i < Count($dtU); $i++) //對每一個用戶,$dtU[$i]
{
$doubleSim=sim($ui, $dtU[$i], $k);
$dtSim[]=array("uid1"=>$ui,"uid2"=>$dtU[$i],"similar"=>$doubleSim);
};
$dtSim=BubbleSort($dtSim,'similar');
return $dtSim;
//按相似度similar 倒序
// return array_multisort($dtSim['similar'],SORT_NUMERIC,SORT_DESC);
}
//--------------- 以下代碼計算ui對pj的預測分 -------------------------------------// //計算用戶ui的對課程的第k項指標的評價的平均分 計算這個是防止用戶習慣性打高分或打低分
function computeUiAvgForK($ui, $k)
{
$db=M('videoscore');
$where=array(
'uid'=>$ui
);
// "select AVG(CAST(才藝滿意度 AS decimal(10, 5))) from 用戶_課程評分 where 用戶編號=@ui";//求平均,因同一用戶的評分
$result=$db->where($where)->avg('skill');
if ($k == 2)//第2個指標
{
//"select AVG(CAST(看滿意度 AS decimal(10, 5))) from 用戶_課程評分 where 用戶編號=@ui";//求平均,
$result=$db->where($where)->avg('effects');
}
if ($k ==3) //第3個指標
{
//"select AVG(CAST(信譽度 AS decimal(10, 5))) from 用戶_課程評分 where 用戶編號=@ui";
$result=$db->where($where)->avg('expression');
}
if($result){
return $result;
}
}
//判斷 用戶ui有沒有給課程pj打過分
function isExistsUi_Pj_Score($ui, $pj)
{
$db=M('videoscore');
//"select 信譽度 from 用戶_課程評分 where 用戶編號=@ui and 課程編號=@pj";//是否評過分
$result=$db->where(array('uid'=>$ui,'tid'=>$pj))->field('expression')->select();
if(!isset($result))//爲空
{
return false;
}
foreach($result as $key=>$v){
$result[$key]=intval($v['expression']);
}
return $result;
}
//取給課程pj的第k個指標打過分的,與用戶ui最相似的n個用戶(用戶給課程打分時,所有三個指標都要打分才能提交)
function getTopN_U_ForPj_To_K($ui,$pj,$k,$n)
{
$counter = 0;
$dtNeighbor=computeSimToUi($ui,$k);//得與ui相似的用戶與相似度並排序好 輸出數組
for ($i = 0; $i < Count($dtNeighbor); $i++) //對每一個用戶,
{
$a=$dtNeighbor[$i]['uid2'];
if (isExistsUi_Pj_Score($dtNeighbor[$i]['uid2'], $pj))
{
$dtResult[]=array('uid1'=>$ui,'uid2'=>$dtNeighbor[$i]['uid2'],'similar'=>$dtNeighbor[$i]['similar']);
$counter++;
}
if ($counter >= $n)
break;
}
return $dtResult;
}
//下面的函數要用到公式
//計算用戶ui對課程pj的第k個指標的預測分,使用最相似的n個用戶(最多n個) 的相度似 sim(ui,uj) 來計算
//表結構爲:用戶編號1,用戶編號2,相似度.第k個指標
function compute_Score_Ui_Pj_K_N($ui,$pj,$k,$n)
{
$dt = getTopN_U_ForPj_To_K($ui, $pj, $k, $n);//表結構爲:用戶編號1,用戶編號2,相似度.第k個指標
foreach($dt as $key=>$v){
//計算該行對應的用戶2,的平均打分,對k指標
$dUjAvg = computeUiAvgForK($v['uid2'], $k);//Ri平均
$dUjToPjForK = getPScore($v['uid2'], $pj, $k);//Rij
$diff = $dUjToPjForK - $dUjAvg; //(Rij-Ri平均)
$dSum0+=floatval($v['similar']) * $diff;//計算分子項
$dSum1 +=floatval($v['similar']); //計算分母項
}
$dSum3 = computeUiAvgForK($ui, $k);//Ri平均
$dResult = $dSum3 + $dSum0 / $dSum1;
return $dResult;
}
//取用戶ui沒有看評價過的課程集合
function getAll_New_Pj_For_Ui($ui)
{
// "select distinct 課程編號 from 用戶_課程評分 where 課程編號 not in (select 課程編號 from 用戶_課程評分 where 用戶編號=@ui)";
$db=M('videoscore');
$result=$db->where(array('uid'=>$ui))->distinct(true)->field('tid')->select();
foreach($result as $key=>$v){
$result[$key]=intval($v['tid']);
}
$map['tid']=array('not in',$result);
$result=$db->where($map)->distinct(true)->field('tid')->select();
foreach($result as $key=>$v){
$result[$key]=intval($v['tid']);//用intval把string轉化爲int
};
// echo dump($result); die;
return $result;
}
//計算用戶ui對沒有看過的課程的預測評分(對第k個評價指標的評分),最多使用n個相似的用戶數據預測
function predict_AllPj_Score_ForUi_To_K($ui,$k,$n)
{
$dtPj = getAll_New_Pj_For_Ui($ui);//得用戶ui沒有看評價過的課程集合
for ($i = 0; $i < Count($dtPj); $i++) //對每一個課程,
{
// pj = dtPj.Rows[i].ItemArray[0].ToString();//得課程編號
$dScore = compute_Score_Ui_Pj_K_N($ui, $dtPj[$i], $k, $n);//計算用戶ui對課程pj的第k個指標的預測分,使用最相似的n個用戶數據(最多n個)
$dtResult[]=array('uid'=>$ui,'tid'=>$dtPj[$i],'predictscore'=>$dScore );//增加行
}
$result=BubbleSort($result,'predictscore');
return $dtResult;
}
//計算用戶ui對沒有看過的課程的綜合預測評分(3個評價指標的評分的加權平均),最多使用n個相似的用戶數據預測,p是權限
function predict_AllPj_Score_ForUi($ui,$p, $n)
{
$dtPj = getAll_New_Pj_For_Ui($ui);//得用戶ui沒有看評價過的課程集合
for ($i = 0; $i < Count($dtPj); $i++) //對每一個課程,
{
// pj = dtPj.Rows[i].ItemArray[0].ToString();//得課程編號
$dScore1 = compute_Score_Ui_Pj_K_N($ui, $dtPj[$i], 1, $n);//計算用戶ui對課程pj的第1個指標的預測分,使用最相似的n個用戶數據(最多n個)
$dScore2 = compute_Score_Ui_Pj_K_N($ui, $dtPj[$i], 2, $n);
$dScore3 = compute_Score_Ui_Pj_K_N($ui, $dtPj[$i], 3, $n);
$dScore4 = $p[0] * $dScore1 + $p[1] * $dScore2 + $p[2] * $dScore3;
$dtResult[]=array('uid'=>$ui,'tid'=>$dtPj[$i],'skill'=>$dScore1,'effects'=>$dScore2,'expression'=>$dScore3,'overall'=>$dScore4);//增加行
}
$result=BubbleSort($dtResult,'overall');
return $result;
}
//排序 從高到低
function BubbleSort($result,$key){
for($i=0;$i<Count($result)-1;$i++)
{
for($j=0;$j<Count($result)-$i-1;$j++){
if($result[$j][$key]<$result[$j+1][$key])
{
$temp=$result[$j];
$result[$j]=$result[$j+1];
$result[$j+1]=$temp;
}
}
}
return $result;
}
以下爲測試數據: uid是用戶id tid是課程id 另外三個是評分指標
uid tid skill effects expression
1 1 5 4 4
2 1 3 3 5
3 2 4 5 5
4 3 5 3 4
1 2 4 4 4
4 4 5 4 3
3 3 5 5 4
2 1 4 5 3
1 3 3 4 4
2 2 3 3 3
3 1 4 4 2
4 1 4 4 5
5 1 2 5 4
5 9 5 3 1
5 2 5 5 5
6 1 1 2 3
6 2 3 1 2
6 4 5 4 3
1 1 3 0 2
1 2 3 0 2
1 8 3 3 3
1 3 3 2 3
2 2 2 5 5
2 1 3 3 1
2 10 3 2 2
2 6 5 5 3
3 6 5 4 3
3 2 3 4 3
3 8 4 2 4
3 3 3 3 0
3 2 2 4 3
4 1 3 2 3
4 2 4 2 3
4 3 4 3 2
8 4 4 3 4
5 9 3 3 3
9 2 4 5 4
5 8 3 2 2
5 4 4 3 3
10 5 4 4 4
5 10 3 3 2
5 5 4 4 4
3 6 3 6 4
6 8 4 4 3
7 5 4 3 3
8 4 1 5 5
9 3 2 3 2
10 7 4 2 4
//shell腳本導入數據庫
#!/bin/bash
#www.cnblogs.com/iloveyoucc/archive/2012/07/10/2585529.html
#https://www.cnblogs.com/fire909090/p/7202584.html
filename='/home/fitch/Desktop/data.txt'
i=0
#連接數據庫
MYSQL="mysql -h localhost -uroot -pfitch --port=3306"
cat $filename | while read uid tid skill effects expression
do
# echo "$i i"
if [ $i -eq 0 ];then
i=$[$i+1]
# echo "o"
else
# echo "$line $i"
# echo $line
sql="use music; insert into hd_videoscore (uid,tid,skill,effects, expression,content,time) values(${uid},${tid},${skill},${effects},${expression},'aaa',1526630425);"
$MYSQL -e "$sql"
fi
done