协同过滤算法代码

2 篇文章 0 订阅

此算法主要用来推荐的.

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




  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值