協同過濾算法代碼

此算法主要用來推薦的.

 //找出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




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章