此算法主要用来推荐的.
//找出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;
}
//下面的函数要用到公式
![](https://img-blog.csdn.net/20180522223729597)
//计算用户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