pagerank python解析

来源:互联网 发布:appstore软件更新不了 编辑:程序博客网 时间:2024/05/18 11:22
相关文章推荐:
http://www.zhimengzhe.com/bianchengjiaocheng/qitabiancheng/116836.html
http://www.cnblogs.com/rubinorth/p/5799848.html

一、介绍摘自维基百科
佩奇排名(PageRank),又称网页排名谷歌左侧排名,是一种由搜索引擎根据网页之间相互的超链接计算的技术,而作为网页排名的要素之一,以Google公司创办人拉里·佩奇(Larry Page)之姓来命名。Google用它来体现网页的相关性和重要性,在搜索引擎优化操作中是经常被用来评估网页优化的成效因素之一。

PageRank通过网络浩瀚的超链接关系来确定一个页面的等级。Google把从A页面到B页面的链接解释为A页面给B页面投票,Google根据投票来源(甚至来源的来源,即链接到A页面的页面)和投票目标的等级来决定新的等级。简单的说,一个高等级的页面可以使其他低等级页面的等级提升。


二、pagerank的多种形态

1、普通型

给定几个网页,每个网页上都有入链和出链,那么该组合是正常的,比如下面这个矩阵M

array([[ 0.,  1.,  1.,  1.,  0.],
       [ 0.,  0.,  0.,  1.,  1.],
       [ 0.,  0.,  0.,  0.,  1.],
       [ 0.,  0.,  0.,  0.,  1.],
       [ 1.,  0.,  0.,  0.,  0.]])

横行表示出链,比如M(1,3)表示有从1网页有一条链接通往3网页,在图中也可以看得出来。


2、终止型
当一个网页只有入链,没有出链的时候,它将会导致其他网页最终停止在这一处。在互联网中,游客应对这种情况的选择是,随机选择一个网页跳转之后继续浏览。因此,这里必须强制性假设,从该网页跳转出去的概率是相等的。比如上面的矩阵一开始是这样的
array([[ 0.,  1.,  1.,  1.,  0.],
       [ 0.,  0.,  0.,  1.,  1.],
       [ 0.,  0.,  0.,  0.,  1.],
       [ 0.,  0.,  0.,  0.,  1.],
       [ 0.,  0.,  0.,  0.,  0.]])
可以看出4网页是没有出链的,那么应当修改如下
array([[ 0.,  1.,  1.,  1.,  0.],
       [ 0.,  0.,  0.,  1.,  1.],
       [ 0.,  0.,  0.,  0.,  1.],
       [ 0.,  0.,  0.,  0.,  1.],
       [ 1.,  1.,  1.,  1.,  1.]])
此时的转移概率为
array([[ 0.        ,  0.33333333,  0.33333333,  0.33333333,  0.        ],
       [ 0.        ,  0.        ,  0.        ,  0.5       ,  0.5       ],
       [ 0.        ,  0.        ,  0.        ,  0.        ,  1.        ],
       [ 0.        ,  0.        ,  0.        ,  0.        ,  1.        ],
       [ 0.2       ,  0.2       ,  0.2       ,  0.2       ,  0.2       ]])
第一行表示从0网页跳转到1,2,3网页的概率被平摊为0.33,其他以此类推。
三、过程
给定各个网页一个初始分值,一般设为平均值,如上面的初始分值为
pr={0: 0.2, 1: 0.2, 2: 0.2, 3: 0.2, 4: 0.2}
在计算中会发现,所有网页加起来的pr值等于1,pr值反应了该网页的重要程度,即该网页被打开的概率大小。利用这个初始分值乘以转移概率,就可以得到简单版的pagerank了。假设B为转移概率的话,下一个pr值就应该是,pr_last=pr*B
其实就是上面的PR(pj)是每次更新的,第一次计算为初始值,1/L(pj)就是转移概率了。
为了更加模拟互联网游客的行为,我们发现,游客停留在网页上有一定的概率,假设为a,那么跳转到另外一个网页的概率假设为1-a,跳转之后会到任意一个网页,N表示所有网页的个数,被打开的概率就是(1-a)/N,a默认为0.85,所以最终公式为
pr_last=a*pr*B+(1-a)/N
将计算的pr_last不断更新到pr值里面,就可以了。
什么时候终止计算呢?当迭代到所有的分配都收敛不变的时候就可以了。然而,一般认为当abs(pr_last-pr)误差不超过1.0e-6,即认为可以终止。
四、代码
写成python代码
一个根据nx.pagerank改编
#coding=utf8from numpy import *  matrix = array([[0,1,1,1,0],             [0,0,0,1,1],             [0,0,0,0,1],             [0,0,0,0,1],             [1,0,0,0,0]],dtype = float)  #dtype指定为float#matrix = array([[0,0,0,0],#             [1,0,0,1],#             [1,1,0,0],#             [1,1,1,0]],dtype = float)  #dtype指定为float    def in_source(martix,id):    return matrix[:,id]def graphMove(matrix):    c = zeros((matrix.shape),dtype = float)      for i in range(matrix.shape[0]):        if matrix[i].sum()==0:            matrix[i]=1        for j in range(matrix.shape[1]):             c[i][j] = matrix[i][j] / (matrix[i].sum())      return cfrom copy import deepcopyclass PRIterator:    __doc__ = '''计算一张图中的PR值'''    def __init__(self):        self.alpha = 0.85  # α        self.max_iterations = 100  # 最大迭代次数        self.min_delta = 0.00001  #阈值       def page_rank(self,matrix):        N = matrix.shape[0]        nodes=[i for i in range(N)]#节点列表        page_rank = dict.fromkeys(nodes, 1.0 / N)  # 给每个节点赋予初始的PR值        page_rank_last = dict.fromkeys(nodes, 1.0 / N)  # 用于下一个PR值的更新        damping_value = (1.0 - self.alpha) / N  # 公式中的(1−α)/N部分        trans_matrix=graphMove(matrix)        flag = False        for i in range(self.max_iterations):            change = 0            for node in nodes:                rank = 0                for id,weight in enumerate(in_source(matrix,node)):                      if weight!=0:                        rank += self.alpha * page_rank[id]*trans_matrix[id][node]                rank += damping_value                page_rank_last[node] = rank            change = sum([abs(page_rank[n] - page_rank_last[n]) for n in page_rank])            page_rank = deepcopy(page_rank_last)                            print("This is NO.%s iteration" % (i + 1))            print(page_rank)            if change < self.min_delta:                flag = True                break        if flag:            print("finished in %s iterations!" % (i+1))        else:            print("finished out of 100 iterations!")        return page_rank

这里面写的复杂了,就是把转移概率和初始概率一个个拆出来算,直接计算两个矩阵相乘也是可以的,如下是根据网页http://blog.csdn.net/gamer_gyt/article/details/47443877修改一些错误而来的:
from numpy import *    a = array([[0,1,1,1,0],             [0,0,0,1,1],             [0,0,0,0,1],             [0,0,0,0,1],             [1,0,0,0,0]],dtype = float)  #dtype指定为float    def graphMove(matrix):    c = zeros((matrix.shape),dtype = float)      for i in range(matrix.shape[0]):        if matrix[i].sum()==0:            matrix[i]=1        for j in range(matrix.shape[1]):             c[i][j] = matrix[i][j] / (matrix[i].sum())      return c  def firstPr(c):     pr = zeros(1*c.shape[0],dtype = float)  #构造一个存放pr值得矩阵      for i in range(c.shape[0]):          pr[i] = float(1)/c.shape[0]      return pr        T=1.0e-6   def pageRank(p,m,v):  #计算pageRank值      id=0    n=firstPr(m) #用于(1-p)*n计算    while(sum([abs((p*dot(v,m) + (1-p)*n)[i]-v[i]) for i in range(len(v))])>T):  #判断pr矩阵是否收敛        v = p*dot(v,m) + (1-p)*n        id+=1#        print (v)    return v,id  if __name__=="__main__":      M = graphMove(matrix)      pr = firstPr(M)      p = 0.85    print (pageRank(p,M,pr))  # 计算pr值   

计算矩阵,得到结果
第一个代码
迭代了46次,阈值时1.0e-5
{0: 0.29634001141493521,
 1: 0.11396289866948645,
 2: 0.11396289866948645,
 3: 0.16239657803320057,
 4: 0.3133376132128915}
第二个代码
迭代了55次,阈值为1.0e-6
{0: 0.10431766467521347, 1: 0.13387433633319062, 2: 0.13387433633319062, 3: 0.19077092927479666, 4: 0.4371627333836087}

textrank也是借鉴了pagerank的原理实现的,在pagerank里面,边的权重都是视为相等的1,表示两个网页之间有连接的相关性,但无法权衡相关性的大小。然而在textrank里面,可以将两个句子的相关性计算出来,句子的相关性矩阵可以采用bm25算法,tfidf算法等等进行计算,得到的结果就是边的权重了,就不像是刚才上面举的例子,除了0全是1的情况,这样的初始权重pr再带入pagerank就得出了句子的重要性排名了。根据排名抽选,组合成为摘要。