PageRank及其用python在spark中实现

来源:互联网 发布:nba新浪数据库 编辑:程序博客网 时间:2024/05/29 19:18

PR值

PR值全称为PageRank(网页级别),PR值是Google用于标识网页的等级、重要性、网站的好坏的重要标准之一。级别从0到10级为满分。PR值越高说明该网页越受欢迎。

例如:一个PR值为1的网站表明这个网站不太具有流行度,而PR值为7到10则表明这个网站非常受欢迎(或者说极其重要)。一般PR值达到4,就算是一个不错的网站了。Google把自己的网站的PR值定到9,这说明Google这个网站是非常受欢迎的,也可以说这个网站非常重要。

如 baidu.com PR值为9,youdao.com PR值为6,可以在 http://pr.chinaz.com/ 中查到

这里写图片描述

这里写图片描述

PageRank算法

PageRank中的page可以理解为网页,也可以理解为Larry Page(算法的发明者),PageRank算法计算每一个网页的PageRank值,然后根据这个值的大小对网页的重要性进行排序。它的思想是模拟一个悠闲的上网者,上网者首先随机选择一个网页打开,然后在这个网页上呆了几分钟后,跳转到该网页所指向的链接,这样无所事事、漫无目的地在网页上跳来跳去,PageRank就是估计这个悠闲的上网者分布在各个网页上的概率。

最简单pagerank模型

互联网中的网页可以看出是一个有向图,其中网页是结点,如果网页A有链接到网页B,则存在一条有向边A->B,下面是一个简单的示例:

这里写图片描述

这个例子中只有四个网页,如果当前在A网页,那么悠闲的上网者将会各以1/3的概率跳转到B、C、D,这里的3表示A有3条出链,如果一个网页有k条出链,那么跳转任意一个出链上的概率是1/k,同理D到B、C的概率各为1/2,而B到C的概率为0。一般用转移矩阵表示上网者的跳转概率,如果用n表示网页的数目,则转移矩阵M是一个n*n的方阵;如果网页j有k个出链,那么对每一个出链指向的网页i,有M[i][j]=1/k,而其他网页的M[i][j]=0;上面示例图对应的转移矩阵如下:

这里写图片描述

初试时,假设上网者在每一个网页的概率都是相等的,即1/n,于是初试的概率分布就是一个所有值都为1/n的n维列向量V0,用V0去右乘转移矩阵M,就得到了第一步之后上网者的概率分布向量MV0,(nXn)*(nX1)依然得到一个nX1的矩阵。下面是V1的计算过程:

这里写图片描述

注意矩阵M中M[i][j]不为0表示用一个链接从j指向i,M的第一行乘以V0,表示累加所有网页到网页A的概率即得到9/24。得到了V1后,再用V1去右乘M得到V2,一直下去,最终V会收敛,即Vn=MV(n-1),上面的图示例,不断的迭代,最终V=[3/9,2/9,2/9,2/9]:

这里写图片描述

终止点问题

上述上网者的行为是一个马尔科夫过程的实例,要满足收敛性,需要具备一个条件:
图是强连通的,即从任意网页可以到达其他任意网页:
互联网上的网页不满足强连通的特性,因为有一些网页不指向任何网页,如果按照上面的计算,上网者到达这样的网页后便走投无路、四顾茫然,导致前面累计得到的转移概率被清零,这样下去,最终的得到的概率分布向量所有元素几乎都为0。假设我们把上面图中C到A的链接丢掉,C变成了一个终止点,得到下面这个图:

这里写图片描述

对应的转移矩阵为:

这里写图片描述

连续迭代下去,最终所有元素都为0:

这里写图片描述

通俗的理解就是C是一个没有链接的网页,点击浏览过程就会停止。

陷阱问题

另外一个问题就是陷阱问题,即有些网页不存在指向其他网页的链接,但存在指向自己的链接。比如下面这个图:

这里写图片描述

上网者跑到C网页后,就像跳进了陷阱,陷入了漩涡,再也不能从C中出来,将最终导致概率分布值全部转移到C上来,这使得其他网页的概率分布值为0,从而整个网页排名就失去了意义。如果按照上面图对应的转移矩阵为:

这里写图片描述

不断的迭代下去,就变成了这样:

这里写图片描述

解决终止点问题和陷阱问题

上面过程,我们忽略了一个问题,那就是上网者是一个悠闲的上网者,而不是一个愚蠢的上网者,我们的上网者是聪明而悠闲,他悠闲,漫无目的,总是随机的选择网页,他聪明,在走到一个终结网页或者一个陷阱网页(比如两个示例中的C),不会傻傻的干着急,他会在浏览器的地址随机输入一个地址,当然这个地址可能又是原来的网页,但这里给了他一个逃离的机会,让他离开这万丈深渊。模拟聪明而又悠闲的上网者,对算法进行改进,每一步,上网者可能都不想看当前网页了,不看当前网页也就不会点击上面的连接,而上悄悄地在地址栏输入另外一个地址,而在地址栏输入而跳转到各个网页的概率是1/n。假设上网者每一步查看当前网页的概率为a,那么他从浏览器地址栏跳转的概率为(1-a),于是原来的迭代公式转化为:

这里写图片描述

现在我们来计算带陷阱的网页图的概率分布:

这里写图片描述

重复迭代下去,得到:

这里写图片描述

完整代码

# coding:utf-8from pyspark import SparkContext, SparkConfdef f(x):    # print x    list1 = []    s = len(x[1][0])    for y in x[1][0]:        list1.append(tuple((y, x[1][1]/s)))    # print list    return list1if __name__== "__main__":    conf = SparkConf()    conf.setMaster("spark://h-pc:7077")    conf.setAppName("PageRank")    # 定义sparkContext    sc = SparkContext(conf=conf)    # 原始数据    list = [('A', ('D',)), ('B', ('A',)), ('C', ('A', 'B')), ('D', ('A', 'C'))]    # 必须转换成key-values,持久化操作提高效率,partitionBy将相同key的元素哈希到相同的机器上,    # 省去了后续join操作shuffle开销    # tuple () 元组    pages = sc.parallelize(list).map(lambda x: (x[0],  tuple(x[1]))).partitionBy(4).cache()    # 初始pr值都设置为1    links = sc.parallelize(['A', 'B', 'C', 'D']).map(lambda x: (x, 1.0))    # 开始迭代    for i in range(1, 100):        # join会把links和page按k合并,如('A',('D',))和('A',1.0) join之后变成 ('A', ('D',1.0))        # flatMap调用了f函数,并把结果平铺        rank = pages.join(links).flatMap(f)        # reduce        links = rank.reduceByKey(lambda x, y: x+y)        # 修正        links = links.mapValues(lambda x: 0.15+0.85*x)    # links.saveAsTextFile("./pagerank")    j = links.collect()    for i in j:        print i

迭代10次

('A', 1.4421445535732418)('B', 0.45715157612820423)      ('C', 0.7371856500325926)('D', 1.3635182202659601)

迭代30次

('A', 1.4358239190773572)                                                       ('B', 0.46128663872364384)('C', 0.7324420437187985)('D', 1.370447398480199)

迭代100次结果

('A', 1.4358225522973844)('B', 0.46128738123240776)('C', 0.7324408970174301)('D', 1.3704491694527767)

原文:
http://blog.csdn.net/gamer_gyt/article/details/47443877

原创粉丝点击