推荐相似度的简单实践
来源:互联网 发布:sql insert 编辑:程序博客网 时间:2024/04/29 01:52
项目中有个模块是读书分享,为了提高粘度,参考了豆瓣等原型后,决定也加上相似度推荐的功能。当然,因为才疏学浅,加上理解不深,做出来的肯定没有豆瓣的强大,但胜在有个雏形,以后也可慢慢扩展。
关于这个,如果对推荐算法不是很理解的朋友,建议可以先看看某大神的博文,当然本博客也有转载【使用欧几里德距离构建简单的推荐系统计算用户相似度】,程序的基本思路便是因此得来的,在本文中不再多说这个算法。
记得那个时候找例子,网上很少php的例子,因此自己写一个,如果能帮到有需要的朋友,便心满意足了,有任何不足之处也欢迎指正。
废话完毕。
本例子的应用是在图书的详细页的底部给出相似书籍推荐,因此在图书详细页程序里,加上一个获取相似度的函数
//推荐$similar = read_get_similar($id);
我已封装为函数,$id是书籍的id。这个函数返回的是相似的书籍信息的二维数组
下面我们看这个函数:
/** * 获取$bookid相似口味的前三个用户,并取得他们也喜欢的书籍 * @param int $bookid 图书id * @return array 书籍数组 * @author mrz * @version 1.0 @2012-4-19 */ function read_get_similar($bookid) { $data = get_similar_data($bookid); $temp = $return = array(); $count = count($data); for ($i = 0; $i < $count; $i++) { //保持索引并取出一个用户基数 $user1 = array_slice($data, $i, 1, true); $uid1 = implode('', array_keys($user1)); $user1 = array_shift($user1); //交叉对比其他用户 for ($j = 0; $j < $count; $j++) { $user2 = array_slice($data, $j, 1, true); $uid2 = implode('', array_keys($user2)); if ($uid1 == $uid2) { continue; } $user2 = array_shift($user2); //获取这两个用户的相同评分书籍条目,与相似度 $cs = getCommonItems($user1, $user2); //如果有共同条目,计算相似度这两个用户的相似度 if ($cs[0] > 0) { $sim = sqrt($cs[1] / (double) $cs[0]); $sim = 1 - tanh($sim); $maxCommonItems = min(count($user1), count($user2)); $sim = $sim * ((double) $cs[0] / (double) $maxCommonItems); $temp[$uid1 . ',' . $uid2] = $sim; } else { $temp[$uid1 . ',' . $uid2] = 0; } } unset($data[$uid1]); $count--; $i = 0; } if (empty($temp)) { //数据不足,返回空 return $return; } else { $index = 0; asort($temp, SORT_NUMERIC); //排序取相似度最近 foreach ($temp as $k => $v) { if ($v !== 0 && $index < 3) { //排除掉没有相似度的并取前三个 $index++; $str .= $k . ','; } } $str = trim($str, ','); //去除掉重复用户 $str = implode(',', array_unique(explode(',', $str))); $query = DB::query("SELECT b.bookid,b.bookname,b.cover FROM " . DB::table('book') . ' b INNER JOIN ' . DB::table('read_record') . " rr ON b.bookid = rr.bookid WHERE FIND_IN_SET(rr.uid,'$str') AND rr.rating>3 GROUP BY rr.bookid ORDER BY rr.time DESC"); while ($row = DB::fetch($query)) { $row['short_bookname'] = cutstr($row['bookname'], 25); //不包含自身 if ($row['bookid'] == $bookid) { continue; } $return[$row['bookid']] = $row; } if (count($return) > 9) { //如果多于9本,取前9本 $return = array_slice($return, 0, 9, true); } return $return; } }
function get_similar_data($bookid) { $return = array(); //查找5个阅读过该图书并评分大于3星的用户 $query = DB::query("SELECT uid,bookid FROM " . DB::table('read_record') . " WHERE bookid = $bookid AND rating > 3 GROUP BY uid ORDER BY time LIMIT 5"); while ($row = DB::fetch($query)) { //查找这5个用户阅读过的书籍的id与评价 $query2 = DB::query("SELECT bookid,rating FROM " . DB::table('read_record') . " WHERE uid = $row[uid] AND bookid!=$row[bookid] LIMIT 5"); while ($row2 = DB::fetch($query2)) { $return[$row['uid']][$row2['bookid']] = $row2['rating']; } } return $return; }
第一个函数里还引用到获取相同条目的函数getCommonItems,如下:
/** * 取得两个用户之间相同的图书数量,计算他们对于每本书的评分差值 * @param array $user1 第一个用户数据数组 * @param array $user2 第二个用户数据数组 * @return array 包含有共同图书,评分差值的数组 * @author mrz */ function getCommonItems($user1, $user2) { $commonItems = 0; $sim = 0; foreach ($user1 as $key1 => $value1) { if (isset($user2[$key1])) { $commonItems++; $sim+=pow($value1 - $user2[$key1], 2); } } return array($commonItems, $sim); }
这个例子就这样结束了。之所以说它简单,是因为三个函数就能基本实现这么一个很有趣的功能。另外我也知道这几个函数写得不怎么样,尤其是对时隔大半年后、看完代码大全的我来说,觉得可以优化的地方实在太多太多。但考虑了一下,决定还是不改动,原汁原味的放上来。(当然,实际项目中肯定会改进的)
1是因为作为示例,有点基础的朋友应该可以看懂了。
2是作为技术水平进步的见证,我得看看以前写的是什么代码,呵呵。
如果要实际测试,必须得要大量数据,而且根据算法来说,是数据越多相似度越精确的。
- 推荐相似度的简单实践
- 使用欧几里德距离构建简单的推荐系统计算用户相似度
- 使用欧几里德距离构建简单的推荐系统计算用户相似度
- 简单的推荐系统搭建--Python(pearson,欧几里得相似度)
- 最简单的推荐系统实践
- 推荐系统 - 1 - 相似度
- 基于社区划分和用户相似度的好友推荐
- 基于欧式距离定义相似度推荐算法的评估
- 协同过滤推荐算法-----向量之间的相似度
- 推荐算法:基于图的算法:基于路相似度
- 基于pearson(皮尔逊)相似度的用户推荐算法
- 一种优化组合相似度的协同过滤推荐算法
- 推荐系统的几种相似度计算
- 推荐算法之Jaccard相似度与Consine相似度
- 构建基于相似用户的推荐
- 统计各推荐组合中的某个商品与预测商品的相似度(最高相似度)
- 推荐系统:常用相似度计算方法
- 推荐系统中的相似度度量
- Django的安装和第一个工程的建立
- Could not instantiate class named NSLayoutConstraint
- android sw watchdog and How to Debug
- 冒泡排序:大泡
- HDU 1711 Number Sequence(KMP入门)
- 推荐相似度的简单实践
- cuda之旅
- IOS开发之所有类型的UIKeyboardType图片展示
- Servlet总结
- 快学Scala习题解答—第三章 数组相关操作
- Android Fragment使用
- 真正优秀的程序员有哪些与众不同之处?
- sqlserver2008查询分析器中显示行号
- PHP學習smarty 變量 自定義函數等