基于图的模型(graph−basedmodelgraph-based modelgraph−basedmodel)是推荐系统中的重要内容。在研究基于图的模型之前,首先需要将用户行为数据表示成图的形式。这里我们将用户行为数据用二分图表示,例如用户数据是由一系列的二元组(也可以使用列表)组成,其中每个元组 (u,i)(u,i)(u,i) 表示用户 uuu 对物品 iii 产生过行为。下图为 AAA, BBB, CCC 用户感兴趣的音乐:

  产生的二分图模型如下:

  将用户行为表示为二分图模型后,下面的任务就是在二分图上给用户进行个性化推荐。如果将个性化推荐算法放到二分图模型上,那么给用户 uuu 推荐物品的任务就可以转化为度量用户顶点 vuv_uvu​ 和与 vuv_uvu​ 没有边直接相连的物品节点在图上的相关性,相关性越高的物品在推荐列表中的权重就越高。
  度量图中两个顶点之间相关性的方法很多,但一般来说图中顶点的相关性主要取决于下面3个因素:
    1. 两个顶点之间的路径数;
    2. 两个顶点之间路径的长度;
    3. 两个顶点之间的路径经过的顶点。
  而相关性高的一对顶点一般具有如下特征:
    1. 两个顶点之间有很多路径相连;
    2. 连接两个顶点之间的路径长度都比较短;
    3. 连接两个顶点之间的路径不会经过出度比较大的顶点。

  我们可以举个例子来说明,如上图,用户 AAA 没有对《故乡的原风景》《偷功》有直接表达喜好,但是可以通过 {A,英雄的黎明,B,故乡的原风景}\{A, 英雄的黎明, B, 故乡的原风景\}{A,英雄的黎明,B,故乡的原风景}, {A,最后的莫西干人,B,故乡的原风景}\{A, 最后的莫西干人, B, 故乡的原风景\}{A,最后的莫西干人,B,故乡的原风景} 两条路径为 333 的路径对《故乡的原风景》产生联系,同样也可以通过 {A,最后的莫西干人,C,偷功}\{A, 最后的莫西干人, C, 偷功\}{A,最后的莫西干人,C,偷功} , {A,最后的莫西干人,B,偷功}\{A, 最后的莫西干人, B, 偷功\}{A,最后的莫西干人,B,偷功} 两条路径为 333 的路径对《偷功》产生联系。那么,用户 AAA 与《偷功》之间的相关性要高于用户 AAA 与《故乡的原风景》,因而《偷功》在用户 AAA 的推荐列表中应该排在《故乡的原风景》之前。而 {A,最后的莫西干人,C,偷功}\{A, 最后的莫西干人, C, 偷功\}{A,最后的莫西干人,C,偷功} 经过点的出度为 {2,3,2,2}\{2, 3, 2, 2\}{2,3,2,2} ,{A,最后的莫西干人,B,偷功}\{A, 最后的莫西干人, B, 偷功\}{A,最后的莫西干人,B,偷功} 经过点的出度为 {2,3,4,2}\{2, 3, 4, 2\}{2,3,4,2} ,所以 {A,最后的莫西干人,B,偷功}\{A, 最后的莫西干人, B, 偷功\}{A,最后的莫西干人,B,偷功} 对 {A−>偷功}\{A->偷功\}{A−>偷功} 的贡献要大于 {A,最后的莫西干人,C,偷功}\{A, 最后的莫西干人, C, 偷功\}{A,最后的莫西干人,C,偷功}。

  下面内容参考《推荐系统实践》。基于上面的例子,产生了基于随机游走的 PersonalRankPersonalRankPersonalRank 算法。假设要给用户 uuu 进行个性化推荐,可以从用户 uuu 对应的节点 vuv_uvu​ 开始在用户物品二分图上进行随机游走。游走到任何一个节点时,首先按照概率 ααα 决定是继续游走,还是停止这次游走并从 vuv_uvu​ 节点开始重新游走。如果决定继续游走,那么就从当前节点指向的节点中按照均匀分布随机选择一个节点作为游走下次经过的节点。这样,经过很多次随机游走后,每个物品节点被访问到的概率会收敛到一个数。最终的推荐列表中物品的权重就是物品节点的访问概率。
PR(V)={(1−alpha)+α∑v′∈in(v)PR(v′)∣out(v′)∣(v=vu)α∑v′∈in(v)PR(v′)∣out(v′)∣(v≠vu)PR(V) = \{ _{(1 - alpha) + \alpha \sum\limits_{v' \in in(v)}^{} {\frac{{PR(v')}}{{|out(v')|}}(v = {v_u})} }^{\alpha \sum\limits_{v' \in in(v)}^{} {\frac{{PR(v')}}{{|out(v')|}}(v \ne {v_u})} }PR(V)={(1−alpha)+αv′∈in(v)∑​∣out(v′)∣PR(v′)​(v=vu​)αv′∈in(v)∑​∣out(v′)∣PR(v′)​(v​=vu​)​

1. 实例分析
  我们就是使用上面的例子来完整实现一个简单的推荐:

  • 数据准备
    实际使用的数据肯定不像我自己编的这么工整,具体数据具体分析。
 def load_data(file_path):records = []f = open(file_path, "r", encoding="utf-8")for line in f:info = line.strip().split("\t")records.append(info)return records

  获得标准数据集如下所示:

 数据集:  [['A', '英雄的黎明'], ['A', '最后的莫西干人'], ['B', '英雄的黎明'], ['B', '故乡的原风景'], ['B', '最后的莫西干人'], ['B', '偷功'], ['C', '最后的莫西干人'], ['C', '偷功']]
  • 数据处理
    有了数据集,我们就需要找出顶点及游走路径,我们这里需要获取用户顶点,歌曲顶点:
 def calc_user_item(records):  # 建立物品-用户的倒排列表user_item = dict()item_user = dict()for user, item in records:user_item.setdefault(user, dict())user_item[user].setdefault(item, 0)user_item[user][item] = 1   # 用户顶点item_user.setdefault(item, dict())item_user[item].setdefault(user, 0)item_user[item][user] = 1   # 物品顶点  print("用户顶点: ", user_item)print("物品顶点: ", item_user)return user_item, item_user
 用户顶点:  {'A': {'英雄的黎明': 1, '最后的莫西干人': 1}, 'B': {'英雄的黎明': 1, '故乡的原风景': 1, '最后的莫西干人': 1, '偷功': 1}, 'C': {'最后的莫西干人': 1, '偷功': 1}}物品顶点:  {'英雄的黎明': {'A': 1, 'B': 1}, '最后的莫西干人': {'A': 1, 'B': 1, 'C': 1}, '故乡的原风景': {'B': 1}, '偷功': {'B': 1, 'C': 1}}

  有了顶点,但是我们需要将其整理到一个顶点数据集中:

 def initGraph(user_item, item_user):G= dict()G= dict(user_item, **item_user)print("G: ", G)return G

  完整的顶点集合如下:

G:  {'A': {'英雄的黎明': 1, '最后的莫西干人': 1}, 'B': {'英雄的黎明': 1, '故乡的原风景': 1, '最后的莫西干人': 1, '偷功': 1}, 'C': {'最后的莫西干人': 1, '偷功': 1}, '英雄的黎明': {'A': 1, 'B': 1}, '最后的莫西干人': {'A': 1, 'B': 1, 'C': 1}, '故乡的原风景': {'B': 1}, '偷功': {'B': 1, 'C': 1}}
  • 算法实现
      获取顶点集合后,我们数据处理算是完成,接下来就需要使用PersonalRankPersonalRankPersonalRank来计算每个节点的访问概率,这里我设置 alphaalphaalpha 为 0.850.850.85,初始节点为 AAA ,最大步数为 100100100:
 # G: 二分图     alpha:随机游走概率     root: 初始节点     max_step: 最大游走步数def PersonalRank(G, alpha, root, max_step):rank = dict()rank = {x:0 for x in G.keys()}rank[root] = 1for k in range(max_step):tmp = {x:0 for x in G.keys()}for i, ri in G.items():               # i 是顶点。ri 是与其相连的顶点及其边的权重 for j, wij in ri.items():     # j 是 i 的连接顶点,wij 是权重  if j not in tmp:tmp[j] = 0tmp[j] += 0.6 * rank[i] / (1.0 * len(ri))if j == root:tmp[j] += 1 - alpha   # 很多博主说这段放在这里会影响,我暂时没发现,希望清楚原因的可以帮我解惑rank = tmprec = sorted(rank.items(),key = lambda x:x[1],reverse = True)   # 将推荐歌曲按兴趣度排名print("节点访问概率: ", rec)return rank 

  不同顶点的访问概率为:

 节点访问概率: [('A', 0.3618098988777181), ('最后的莫西干人', 0.12940492021276595), ('英雄的黎明', 0.11976304945054946), ('B', 0.07480053191489362), ('C', 0.032139569207388356), ('偷功', 0.020861950549450545), ('故乡的原风景', 0.011220079787234041)]
  • 推荐

有了每个顶点的访问概率,即用户和歌曲的访问概率,我们就可以开始给用户推荐了,我们这里就给用户 AAA 推荐歌曲,因为顶点有用户顶点和歌曲顶点,所以我们去掉用户顶点和推荐用户本身已经感兴趣的顶点:

 def Recommend(user, rank, user_item):rec = []for music in rank:data = music[0]rec.append(data)for u, v in user_item.items():          # 移除用户顶点for i in rec:if i == u:rec.remove(i)for u, v in user_item[user].items():  # 移除用户已经标记过的歌曲for i in rec:if i == u:rec.remove(i)return rec   

  最终推荐结果为:

 推荐物品:  ['偷功', '故乡的原风景']

2. 算法改进
  本章节内容摘抄自《推荐系统实践》。虽然 PersonalRankPersonalRankPersonalRank 算法可以通过随机游走进行比较好的理论解释,但该算法在时间复杂度上有明显的缺点。因为在为每个用户进行推荐时,都需要在整个用户物品二分图上进行迭代,直到整个图上的每个顶点的 PRPRPR 值收敛。这一过程的时间复杂度非常高,不仅无法在线提供实时推荐,甚至离线生成推荐结果也很耗时。
  为了解决PersonalRank每次都需要在全图迭代并因此造成时间复杂度很高的问题,这里给出两种解决方案。第一种很容易想到,就是减少迭代次数,在收敛之前就停止。这样会影响最终的精度,但一般来说影响不会特别大。另一种方法就是从矩阵论出发,重新设计算法。对矩阵运算比较熟悉的读者可以轻松将 PersonalRankPersonalRankPersonalRank 转化为矩阵的形式。令 MMM 为用户物品二分图的转移概率矩阵,即:
M(v,v′)=1∣out(v)∣M(v,v') = \frac{1}{{|out(v)|}}M(v,v′)=∣out(v)∣1​
  那么,迭代公式可以转化为:
r=(1−α)r0+αMTr=>r=(1−α)(1−αMT)−1r0r = (1 - \alpha ){r_0} + \alpha {M^T}r = > r = (1 - \alpha ){(1 - \alpha {M^T})^{ - 1}}{r_0}r=(1−α)r0​+αMTr=>r=(1−α)(1−αMT)−1r0​
  因此,只需要计算一次 (1−αMT)−1(1 - \alpha {M^T})^{ - 1}(1−αMT)−1,这里 $(1−αMT)(1 - \alpha {M^T})(1−αMT) 是稀疏矩阵。具体实现后续会继续。

3. 代码分析
基于图的推荐算法

推荐系统实践(五)----基于图的推荐算法相关推荐

  1. 笔记:基于标签的推荐系统、基于图的推荐算法、PersonalRank

    笔记:基于标签的推荐系统.基于图的推荐算法.PersonalRank 发表于11个月前(2015-05-26 19:15)   阅读(44) | 评论(0) 2人收藏此文章, 我要收藏 赞0 原文:h ...

  2. 推荐系统--基于图的推荐算法

    基于图的模型(graph−basedmodel )是推荐系统中的重要内容.在研究基于图的模型之前,首先需要将用户行为数据表示成图的形式.这里我们将用户行为数据用二分图表示,例如用户数据是由一系列的二元 ...

  3. 推荐系统实践(七)----基于邻域的社会化推荐算法

      今年抖音非常火爆和流行,我们在刷抖音的时候,经常会发现给我们刷到自己微信或者是抖音好友喜欢的小视频,这里很多人都就会很好奇,抖音怎么知道这些人是我的好友,甚至知道我和好友的兴趣就一样呢,这就有了基 ...

  4. 《网络电视节目推荐系统----基于用户协同过滤与基于内容的推荐算法的后融合》

    文章目录 一.什么是推荐系统 二.产生原因 由上我们可以得知,推荐系统产生的两大原因 三.应用场景 四.推荐系统的评测方法 1. 推荐系统的三大实验方法 a. 离线实验: b. 用户调查 c. 在线实 ...

  5. 推荐系统实践(二)----基于物品的协同过滤算法(ItemCF)

      上一篇博客我简单讲了一下基于用户的协同过滤算法,这里我们一起来学习一下另一种:基于物品的协同过滤算法.基于物品的协同过滤算法是目前业界应用最多的算法,亚马逊.Netflix.Hulu.YouTub ...

  6. 推荐系统实战(5)——基于内容的推荐算法(CB)

    1 基础CB推荐算法 基础CB推荐算法利用物品的基本信息和用户偏好内容的相似性进行物品推荐.通过分析用户已经浏览过的物品内容,生成用户的偏好内容,然后推荐与用户感兴趣的物品内容相似度高的其他物品. 比 ...

  7. 新闻推荐系统:基于内容的推荐算法(Recommender System:Content-based Recommendation)

    2018/10/04更新 这篇文章似乎被越来越多的小伙伴看到了,所以觉得有必要做一些进一步的详细说明. 首先按照本文所讲解的推荐思路进行新闻推荐的推荐系统,我已经实现并已经放在Github上了.欢迎小 ...

  8. 新闻推荐系统:基于内容的推荐算法——TFIDF、衰减机制(github java代码)

    转自: 因为开发了一个新闻推荐系统的模块,在推荐算法这一块涉及到了基于内容的推荐算法(Content-Based Recommendation),于是借此机会,基于自己看了网上各种资料后对该分类方法的 ...

  9. 推荐系统-基于内容的推荐算法(Content-Based)

    基于内容的推荐算法(Content-Based) 简介 基于内容的推荐方法是非常直接的,它以物品的内容描述信息为依据来做出的推荐,本质上是基于对物品和用户自身的特征或属性的直接分析和计算. 例如,假设 ...

最新文章

  1. XGBOOST带试验源码
  2. 重新挂载linux分区添加硬盘
  3. [讨论] 线程池 vs 专有线程
  4. 单击浏览器右上角的X弹出提示窗口
  5. 第七届山东省Acm程序设计竞赛赛后总结
  6. linux清理整个磁盘空间,一次Linux磁盘空间清理的经历
  7. linux系统rc路由配置_详解CentOS 6.4 添加永久静态路由所有方法汇总
  8. linux取消头文件链接,【原创】Linux下编译链接中常见问题总结
  9. 负载均衡算法及手段(转)
  10. bootstrapValidator常用验证规则总结
  11. 微博营销推广策略分析
  12. 大数据分析平台洱源县_洱源县专项债可行性研究报告
  13. ps4移植android游戏,安卓玩PS4游戏 remote play安装教程
  14. USACO美国信息学奥赛竞赛12月份开赛,中国学生备赛指南
  15. 学计算机用书包吗,起底大学生活 | 书包物品大揭秘
  16. es时间对象(Date)
  17. 100集华为HCIE安全培训视频教材整理 | IPSec VdPdN高可靠性案例及配置(四)
  18. linux jsp 编译报错,JSP简要介绍
  19. Cloudera CDH 常见的版本
  20. 黑牛外汇交易系统简介-------稳定盈利的外汇交易系统

热门文章

  1. REARGUARD Secure Keyword SearchUsing Trusted Hardware 论文详读
  2. 可升级鸿蒙的设备,华为鸿蒙即将到来,华为终于“出手”了!哪些机型可升级? - 王石头...
  3. openlayers 6 图层望远镜功能的实现
  4. 如何实现报表数据的动态层次钻取(一)
  5. 软件项目管理案例教程-韩万江-期末复习
  6. 阴历转阳历java_GitHub - opprime/calendarist: 一个可实现阳历、阴历、干支历间相互转换的JAVA工具...
  7. python 将列表中的英文或者拼音转换为中文
  8. 特斯拉如何恢复出厂设置_iphone如何恢复手机出厂设置
  9. Spring Boot入门系列(六)Spring Boot如何使用Mybatis XML 配置版【附详细步骤】
  10. android卡在gradle,Android Studio打开新项目卡在Gradle的问题