时间:2017年5月 出处:http://blog.csdn.net/csearch/article/details/71315610 声明:版权所有,转载请联系作者并注明出
在推荐系统中,用户对物品的行为数据可以转化成图的形式,具体来说,可以转化为二分图进行表示,基于图来考虑推荐问题也是一种常用的思路之一。
PageRank是Google网页排序的经典算法,这里只做简要概述,详细的算法推导过程及实现,可以网上找找相关资料,挺多的。 PageRank是Larry Page 和 Sergey Brin设计的用来衡量特定网页相对于搜索引擎中其他网页的重要性的算法,其计算结果作为google搜索结果中网页排名的重要指标。 * 网页之间通过超链接相互连接,互联网上不计其数的网页就构成了一张超大的图。 * PageRank假设用户从所有网页中随机选择一个网页进行浏览,然后通过超链接在网页直接不断跳转。 * 算法令用户继续浏览的概率为d,用户以相等的概率在当前页面的所有超链接中随机选择一个继续浏览。 * 这是一个随机游走的过程。当经过很多次这样的游走之后,每个网页被访问用户访问到的概率就会收敛到一个稳定值。这个概率就是网页的重要性指标,被用于网页排名。
算法迭代关系式如下所示:
PR(i)=1−alphaN+alpha∑i∈in(i)PR(j)|outer(j)| 上式中 * PR(i)是网页i的访问概率(也就是重要度) * alpha是用户继续访问网页的概率 * N是网页总数 * in(i)表示指向网页i的网页集合 * out(j)表示网页j指向的网页集合接下来我们分析一下这个公式,网页i被访问到的概率由两部分组成: * 第一部分是网页i作为起点,第一个被和用户点击后停留在当前页面的概率,即: 1−alphaN * 第二部分是用户点击其他网页后(无论网页i是不是起点),再次跳转回到网页i的概率: alpha∑i∈in(i)PR(j)|outer(j)| 这两部分的和便是网页i被点击到的概率。
很多情况下,我们会从已有的模型中去推(套)演(用)到新的场景中,进一步观察这个模型在新的场景下是否有可取之处? 那么,从上述PageRank算法做简单的推演,我们用user节点和item节点替换上面的网页节点就可以计算出每个user,每个item在全局的重要性,给出全局的排名,显然这并不是我们想要的,我们需要计算的是物品节点相对于某一个用户节点u的相关性。 那具体该怎么做呢?Standford的Haveliwala于2002年在他《Topic-sensitive pagerank》一文中提出了PersonalRank算法,该算法能够为用户个性化的对所有物品进行排序。它的迭代公式如下:
PR(i)=(1−d)ri+d∑j∈in(i)PR(j)|outer(i)| * ri=1,i=u * ri=0,i≠u我们发现PersonalRank跟PageRank的区别只是用 ri 替换了1/N,也就是说从不同点开始的概率不同。u表示我们推荐的目标用户,这样使用上式计算的就是所有顶点相对于顶点u的相关度。
对于相关性高的顶点有如下的定义: (1)两个顶点之间有很多路径相连。 (2)连接两个顶点之间的路径长度都比较短。 (3)连接两个顶点之间的路径不会经过度比较大的顶点。 上面有一个概念需要理解,度,顶点的度是指和该顶点相关联的边数。
与PageRank随机选择一个点开始游走(也就是说从每个点开始的概率都是相同的)不同,如果我们要计算所有节点相对于用户u的相关度,则PersonalRank从用户u对应的节点开始游走,每到一个节点都以1-d的概率停止游走并从u重新开始,或者以d的概率继续游走,从当前节点指向的节点中按照均匀分布随机选择一个节点往下游走。这样经过很多轮游走之后,每个顶点被访问到的概率也会收敛趋于稳定,这个时候我们就可以用概率来进行排名了。
在执行算法之前,我们需要初始化每个节点的初始概率值。如果我们对用户u进行推荐,则令u对应的节点的初始访问概率为1,其他节点的初始访问概率为0,然后再使用迭代公式计算。而对于pageRank来说,由于每个节点的初始访问概率相同,所以所有节点的初始访问概率都是1/N (N是节点总数)。
输出 (‘user_cnt: ‘, 943, ‘, movie_cnt: ‘, 1650) Out[17]: UserID MovieID Score Time 0 1 1 5 874965758 1 1 2 3 876893171 2 1 3 4 878542960 3 1 4 3 876893119 4 1 5 3 889751712
输出 CPU times: user 15.3 s, sys: 118 ms, total: 15.4 s Wall time: 15.4 s 9746
PersonalRank算法,这个算法是基于pageRank算法进行了一些变化,在pageRank算法中,计算出来的是每一个顶点相对其他顶点的相关性,代入到我们的用户物品二分图中,这显然不是我们想要的,我们需要的是所有物品相对于特定某个用户的相关性,有公式如下: PR(u)=(1−alpha)ru+alpha∑i∈in(u)PR(i)|outer(i)| ru=1,u=root ru=0,u≠root 对比pageRank,不同点只在于r的值不同,root代表根节点,即我们的目标用户节点,意思便是我们每次都是从目标用户节点出发,进行随机游走,而不同于pageRank的起点是随机从所有网页中进行选择,personalRank算法得出的结果便是所有顶点相对于目标用户结点的相关性。
def personalRank(G, alpha, userID, iterCount=20): ''''' 随机游走迭代 :param G: 二分图 :param alpha: 随机游走的概率 :param userID: 目标用户 :param iterCount: 迭代次数 :return: series ''' rank = {g: 0 for g in G.keys()} rank['u'+str(userID)] = 1 # 根节点为起点选择概率为1,其他顶点为0 for k in range(iterCount): # 按设定的迭代次数进行迭代运算 tmp = {g: 0 for g in G.keys()} for i, ri in G.items(): #遍历每一个顶点 for j, wij in ri.items(): #遍历每个顶点连接的顶点 tmp[j] += alpha * rank[i] / len(ri) tmp['u' + str(userID)] += 1 - alpha #根顶点r=1,加上1-alpha rank = tmp series = pd.Series(list(rank.values()), index=list(rank.keys())) series = series.sort_values(ascending=False) return series #返回排序后的series # 计算userID为1的personalRank图模型 %time s = personalRank(G, alpha=0.6, userID=1, iterCount=20) print s.size输出 9746
输出 CPU times: user 44.7 ms, sys: 1.18 ms, total: 45.9 ms Wall time: 45.3 ms [{‘i2858’: 0.00050075131015363185}, {‘i1196’: 0.00043310276435962858}, {‘i1210’: 0.00041226057350608546}, {‘i593’: 0.00038068361173254449}, {‘i480’: 0.00036954608314440505}, {‘i1198’: 0.00036616397789523248}, {‘i2396’: 0.00036178614890107583}, {‘i2571’: 0.00035883917557775883}, {‘i589’: 0.0003587179505317039}, {‘i110’: 0.00034614943986419495}]
参考文档 * 用PersonalRank实现基于图的推荐算法
