PageRank 算法

1. 算法来源

谷歌的两位创始人,当时还是美国斯坦福大学 (Stanford University) 研究生的佩奇 (Larry Page) 和布林 (Sergey Brin) 开始了对网页排序问题的研究。他们的借鉴了学术界评判学术论文重要性的通用方法, 那就是看论文的引用次数。由此想到网页的重要性也可以根据这种方法来评价。于是PageRank的核心思想就诞生了2,非常简单:

 

  1. 如果一个网页被很多其他网页链接到的话说明这个网页比较重要,也就是PageRank值会相对较高
  2. 如果一个PageRank值很高的网页链接到一个其他的网页,那么被链接到的网页的PageRank值会相应地因此而提高

在这里插入图片描述

2. 算法原理

PageRank算法简单来说分为两步:

  1. 给每个网页一个PR值(下面用PR值指代PageRank值)
  2. 通过(投票)算法不断迭代,直至达到平稳分布为止。

互联网中的众多网页可以看作一个有向图。下图是一个简单的例子

图1-1

A、B、C三个页面都链入D页面,则D的PR值将是A、B、C三个页面PR值的总和:    PR(D)=PR(A)+PR(B)+PR(C)

 

继续上面的假设,A除了链接到D以外,A还链接了C和B,那么当用户访问 A 的时候,就有跳转到 B、C 或者 D 的可能性,跳转概率均为 1/3。在计算D的PR值时,A的PR值只能投出1/3​的票,B的PR值只能投出 1/2 ​的票,而C只链接到D,所以能投出全票,所以A的PR值总和应为:     

               PR(D)=PR(A)/3+PR(B)/2+PR(C)

所以可以得出一个网页的PR值计算公式应为

              

 

其中,Bu是所有链接到网页u的网页集合,网页v是属于集合Bu​的一个网页,L(v)则是网页v的对外链接数(即出度)

代码:

a=0.25 
b=0.25
c=0.25 
d=0.25
for i in range(20):
    print(a,b,c,d)
    a1=a
    b1=b
    c1=c
    d1=d
    a=1/2*b1
    b=1/3*a1+d1
    c=1/3*a1
    d=1/3*a1+c1+1/2*b1

      PageRank 算法_第1张图片

十多轮迭代后  PR值逐渐收敛 稳定     PR(B)值最高

2.1 排名泄露

如果存在网页没有出度链接,如A节点所示,则会产生排名泄露问题,经过多次迭代后,所有网页的PR只都趋向于0。

                   PageRank 算法_第2张图片

后边趋近与零

PageRank 算法_第3张图片

2.1.1 解决办法

 图中的A网页没有出链,对其他网页没有PR值的贡献,为了满足 Markov 链的收敛性,于是我们设定其对所有的网页(包括它自己)都有出链,则此图中B的PR值可表示为:

        

2.2 排名下沉

 若网页没有入度链接,如节点A所示,经过多次迭代后,A的PR值会趋向于0。

          PageRank 算法_第4张图片 PageRank 算法_第5张图片

2.3 排名上升

互联网中一个网页只有对自己的出链,或者几个网页的出链形成一个循环圈。那么在不断地迭代过程中,这一个或几个网页的PR值将只增不减。如下图中的C网页:

               PageRank 算法_第6张图片 迭代多次 c接近1 其他为0

为了解决这个问题。我们想象一个随机浏览网页的人,当他到达C网页后,显然不会傻傻地一直被C网页的小把戏困住。我们假定他有一个确定的概率会输入网址直接跳转到一个随机的网页,并且跳转到每个网页的概率是一样的。

于是则此图中C的PR值可表示为:

在一般情况下,一个网页的PR值计算如下:

其中Mpi是所有对pi​网页有出链的网页集合,L ( pj)是网页pj​的出链数目,N是网页总数,α 一般取0.85(很多论文都取0.85)。

根据上面的公式,我们可以计算每个网页的PR值,在不断迭代趋于平稳的时候,即为最终结果。具体怎样算是趋于平稳,我们在下面的PR值计算方法部分再做解释。

3. 算法证明

PageRank 算法_第7张图片

PageRank算法的正确性证明包括上面两点。为了方便证明,我们先将PR值的计算方法转换一下。

                PageRank 算法_第8张图片

我们可以用一个矩阵来表示这张图的出链入链关系,Sij = 0表示j网页没有对i网页的出链:

                PageRank 算法_第9张图片

取E为所有分量都为 1 的列向量,接着定义矩阵:

则PR值的计算如下,其中Pn 为第n次迭代时各网页PR值组成的列向量:

于是计算PR值的过程就变成了一个 Markov 过程,那么PageRank算法的证明也就转为证明 Markov 过程的收敛性证明:如果这个 Markov 过程收敛,那么 存 在 , 且 与 p0选取无关。

若一个 Markov 过程收敛,那么它的状态转移矩阵A需要满足:

  1. A为随机矩阵。
  2. A是不可约的。
  3. A是非周期的

第一点,随机矩阵又叫概率矩阵或 Markov 矩阵,满足以下条件:

显然我们的A矩阵所有元素都大于等于0,并且每一列的元素和都为1。所以A矩阵为左随机矩阵。

第二点,不可约矩阵:方阵A是不可约的当且仅当与A对应的有向图是强联通的。有向图G=(V,E)是强联通的当且仅当对每一对节点对u,v∈V,存在从u到v的路径。

因为我们在之前设定用户在浏览页面的时候有确定概率通过输入网址的方式访问一个随机网页,所以A矩阵同样满足不可约的要求。

第三点,要求A是非周期的。

所谓周期性,体现在Markov链的周期性上,即,在经历一段转移之后必然会回到链中的某个位置并开始循环。若A的幂具有周期性,那么这个Markov链的状态就是周期性变化的。

因为A是素矩阵(素矩阵指自身的某个次幂为正矩阵的矩阵),所以A是非周期的。

至此,我们证明了PageRank算法的正确性。

4. PR值计算方法

4.1 幂迭代法

首先给每个页面赋予随机的PR值,然后通过不断地迭代PR值。当满足下面的不等式后迭代结束,获得所有页面的PR值

4.2 特征值法

当上面提到的Markov链收敛时,必有:

4.3 代数法

相似的,当上面提到的Markov链收敛时,必有:

PageRank 算法_第10张图片

5. 算法实现

   基于迭代法的简单实现

用python实现,需要先安装python-graph-core。

# -*- coding: utf-8 -*-

from pygraph.classes.digraph import digraph


class PRIterator:
    __doc__ = '''计算一张图中的PR值'''

    def __init__(self, dg):
        self.damping_factor = 0.85  # 阻尼系数,即α
        self.max_iterations = 100  # 最大迭代次数
        self.min_delta = 0.00001  # 确定迭代是否结束的参数,即ϵ
        self.graph = dg

    def page_rank(self):
        #  先将图中没有出链的节点改为对所有节点都有出链
        for node in self.graph.nodes():
            if len(self.graph.neighbors(node)) == 0:
                for node2 in self.graph.nodes():
                    digraph.add_edge(self.graph, (node, node2))

        nodes = self.graph.nodes()
        graph_size = len(nodes)

        if graph_size == 0:
            return {}
        page_rank = dict.fromkeys(nodes, 1.0 / graph_size)  # 给每个节点赋予初始的PR值
        damping_value = (1.0 - self.damping_factor) / graph_size  # 公式中的(1−α)/N部分

        flag = False
        for i in range(self.max_iterations):
            change = 0
            for node in nodes:
                rank = 0
                for incident_page in self.graph.incidents(node):  # 遍历所有“入射”的页面
                    rank += self.damping_factor * (page_rank[incident_page] / len(self.graph.neighbors(incident_page)))
                rank += damping_value
                change += abs(page_rank[node] - rank)  # 绝对值
                page_rank[node] = rank

            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!" % node)
        else:
            print("finished out of 100 iterations!")
        return page_rank


if __name__ == '__main__':
    dg = digraph()

    dg.add_nodes(["A", "B", "C", "D", "E"])

    dg.add_edge(("A", "B"))
    dg.add_edge(("A", "C"))
    dg.add_edge(("A", "D"))
    dg.add_edge(("B", "D"))
    dg.add_edge(("C", "E"))
    dg.add_edge(("D", "E"))
    dg.add_edge(("B", "E"))
    dg.add_edge(("E", "A"))

    pr = PRIterator(dg)
    page_ranks = pr.page_rank()

    print("The final page rank is\n", page_ranks)

6. PageRank算法的缺点

这是一个天才的算法,原理简单但效果惊人。然而,PageRank算法还是有一些弊端。所以其实google本身也在不断改进这个算法。

第一,没有区分站内导航链接。很多网站的首页都有很多对站内其他页面的链接,称为站内导航链接。这些链接与不同网站之间的链接相比,肯定是后者更能体现PageRank值的传递关系。

第二,没有过滤广告链接和功能链接(例如常见的“分享到微博”)。这些链接通常没有什么实际价值,前者链接到广告页面,后者常常链接到某个社交网站首页。

第三,对新网页不友好。一个新网页的一般入链相对较少,即使它的内容的质量很高,要成为一个高PR值的页面仍需要很长时间的推广。

 

针对PageRank算法的缺点,有人提出了TrustRank算法。其最初来自于2004年斯坦福大学和雅虎的一项联合研究,用来检测垃圾网站。TrustRank算法的工作原理:先人工去识别高质量的页面(即“种子”页面),那么由“种子”页面指向的页面也可能是高质量页面,即其TR值也高,与“种子”页面的链接越远,页面的TR值越低。“种子”页面可选出链数较多的网页,也可选PR值较高的网站。

TrustRank算法给出每个网页的TR值。将PR值与TR值结合起来,可以更准确地判断网页的重要性。

你可能感兴趣的:(自然语言处理,NLP,机器学习,算法,python,深度学习,数据挖掘,自然语言处理)