一、什么是pagerank

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

PageRank的核心思想非常简单:

如果一个网页被很多其他网页链接到的话说明这个网页比较重要,也就是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上来,这使得其他网页的概率分布值为0,从而整个网页排名就失去了意义。如果按照上面图对应的转移矩阵为:

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

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

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


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

重复迭代下去,得到:

六、用Python实现Page Rank算法

Python 实现的PageRank算法,纯粹使用python原生模块,没有使用numpy、scipy。这个程序实现还比较原始,可优化的地方较多。

  1. # -*- coding:utf-8 -*-
  2. import random
  3.  
  4. N = 4 # 四个网页
  5. d = 0.85 # 阻尼因子为0.85
  6. delt = 0.00001 # 迭代控制变量
  7.  
  8. # 两个矩阵相乘
  9. def matrix_multi(A, B):
  10. result = [[0] * len(B[0]) for i in range(len(A))]
  11. for i in range(len(A)):
  12. for j in range(len(B[0])):
  13. for k in range(len(B)):
  14. result[i][j] += A[i][k] * B[k][j]
  15. return result
  16.  
  17. # 矩阵A的每个元素都乘以n
  18. def matrix_multiN(n, A):
  19. result = [[1] * len(A[0]) for i in range(len(A))]
  20. for i in range(len(A)):
  21. for j in range(len(A[0])):
  22. result[i][j] = n * A[i][j]
  23. return result
  24.  
  25. # 两个矩阵相加
  26. def matrix_add(A, B):
  27. if len(A[0]) != len(B[0]) and len(A) != len(B):
  28. return
  29. result = [[0] * len(A[0]) for i in range(len(A))]
  30. for i in range(len(A)):
  31. for j in range(len(A[0])):
  32. result[i][j] = A[i][j] + B[i][j]
  33. return result
  34.  
  35. def pageRank(A):
  36. e = []
  37. for i in range(N):
  38. e.append(1)
  39. norm = 100
  40. New_P = []
  41. for i in range(N):
  42. New_P.append([random.random()])
  43. r = [[(1 - d) * i * 1 / N] for i in e]
  44. while norm > delt:
  45. P = New_P
  46. New_P = matrix_add(r, matrix_multiN(d, matrix_multi(A, P))) # P=(1-d)*e/n+d*M'P PageRank算法的核心
  47. norm = 0
  48. # 求解矩阵一阶范数
  49. for i in range(N):
  50. norm += abs(New_P[i][0] - P[i][0])
  51. print New_P
  52.  
  53. # 根据邻接矩阵求转移概率矩阵并转向
  54. def tran_and_convert(A):
  55. result = [[0] * len(A[0]) for i in range(len(A))]
  56. result_convert = [[0] * len(A[0]) for i in range(len(A))]
  57. for i in range(len(A)):
  58. for j in range(len(A[0])):
  59. result[i][j] = A[i][j] * 1.0 / sum(A[i])
  60. for i in range(len(result)):
  61. for j in range(len(result[0])):
  62. result_convert[i][j] = result[j][i]
  63. return result_convert
  64.  
  65. def main():
  66. A = [[0, 1, 1, 0], \
  67. [1, 0, 0, 1], \
  68. [1, 0, 0, 1], \
  69. [1, 1, 0, 0]]
  70. M = tran_and_convert(A)
  71. pageRank(M)
  72.  
  73. if __name__ == '__main__':
  74. main()

 还有另外一个算法是用了numpy数组的

  1. # -*- coding: utf-8 -*-
  2. from numpy import *
  3.  
  4. a = array([[0, 1, 1, 0],
  5. [1, 0, 0, 1],
  6. [1, 0, 0, 1],
  7. [1, 1, 0, 0]], dtype=float) # dtype指定为float
  8.  
  9. def graphMove(a): # 构造转移矩阵
  10. b = transpose(a) # b为a的转置矩阵
  11. c = zeros((a.shape), dtype=float)
  12. for i in range(a.shape[0]):
  13. for j in range(a.shape[1]):
  14. c[i][j] = a[i][j] / (b[j].sum()) # 完成初始化分配
  15. # print c,"\n===================================================="
  16. return c
  17.  
  18. def firstPr(c): # pr值得初始化
  19. pr = zeros((c.shape[0], 1), dtype=float) # 构造一个存放pr值得矩阵
  20. for i in range(c.shape[0]):
  21. pr[i] = float(1) / c.shape[0]
  22. # print pr,"\n==================================================="
  23. return pr
  24.  
  25. def pageRank(p, m, v): # 计算pageRank值
  26. while ((v == p * dot(m, v) + (
  27. 1 - p) * v).all() == False): # 判断pr矩阵是否收敛,(v == p*dot(m,v) + (1-p)*v).all()判断前后的pr矩阵是否相等,若相等则停止循环
  28. # print v
  29. v = p * dot(m, v) + (1 - p) * v
  30. # print (v == p*dot(m,v) + (1-p)*v).all()
  31. return v
  32.  
  33. if __name__ == "__main__":
  34. M = graphMove(a)
  35. pr = firstPr(M)
  36. p = 0.85 # 引入浏览当前网页的概率为p,假设p=0.8
  37. print pageRank(p, M, pr) # 计算pr值

幂迭代法的代码

  1. import numpy as np
  2.  
  3. class CPageRank(object):
  4. '''实现PageRank Alogrithm
  5. '''
  6. def __init__(self):
  7. self.PR = [] #PageRank值
  8.  
  9. def GetPR(self, IOS, alpha, max_itrs, min_delta):
  10. '''幂迭代方法求PR值
  11. :param IOS 表示网页出链入链关系的矩阵,是一个左出链矩阵
  12. :param alpha 阻尼系数α,一般alpha取值0.85
  13. :param max_itrs 最大迭代次数
  14. :param min_delta 停止迭代的阈值
  15. '''
  16. #IOS左出链矩阵, a阻尼系数alpha, N网页总数
  17. N = np.shape(IOS)[0]
  18. #所有分量都为1的列向量
  19. e = np.ones(shape=(N, 1))
  20. #计算网页出链个数统计
  21. L = [np.count_nonzero(e) for e in IOS.T]
  22. #计算网页PR贡献矩阵helpS,是一个左贡献矩阵
  23. helps_efunc = lambda ios,l:ios/l
  24. helps_func = np.frompyfunc(helps_efunc, 2, 1)
  25. helpS = helps_func(IOS, L)
  26. #P[n+1] = AP[n]中的矩阵A
  27. A = alpha*helpS + ((1-alpha)/N)*np.dot(e, e.T)
  28. print('左出链矩阵:\n', IOS)
  29. print('左PR值贡献概率矩阵:\n', helpS)
  30. #幂迭代法求PR值
  31. for i in range(max_itrs):
  32. if 0 == np.shape(self.PR)[0]: #使用1.0/N初始化PR值表
  33. self.PR = np.full(shape=(N,1), fill_value=1.0/N)
  34. print('初始化的PR值表:', self.PR)
  35. #使用PR[n+1] = APR[n]递推公式,求PR[n+1]
  36. old_PR = self.PR
  37. self.PR = np.dot(A, self.PR)
  38. #如果所有网页PR值的前后误差 都小于 自定义的误差阈值,则停止迭代
  39. D = np.array([old-new for old,new in zip(old_PR, self.PR)])
  40. ret = [e < min_delta for e in D]
  41. if ret.count(True) == N:
  42. print('迭代次数:%d, succeed PR:\n'%(i+1), self.PR)
  43. break
  44. return self.PR
  45.  
  46. def CPageRank_manual():
  47. #表示网页之间的出入链的关系矩阵,是一个左关系矩阵,可以理解成右入链矩阵
  48. #IOS[i, j]表示网页j对网页i有出链
  49. IOS = np.array([[0, 0, 0, 0, 1],
  50. [1, 0, 0, 0, 0],
  51. [1, 0, 0, 0, 0],
  52. [1, 1, 0, 0, 0],
  53. [0, 1, 1, 1, 0]], dtype=float)
  54. pg = CPageRank()
  55. ret = pg.GetPR(IOS, alpha=0.85, max_itrs=100, min_delta=0.0001)
  56. print('最终的PR值:\n', ret)
  57. if __name__=='__main__':
  58. CPageRank_manual()

运行结果

  1. 左出链矩阵:
  2. [[ 0. 0. 0. 0. 1.]
  3. [ 1. 0. 0. 0. 0.]
  4. [ 1. 0. 0. 0. 0.]
  5. [ 1. 1. 0. 0. 0.]
  6. [ 0. 1. 1. 1. 0.]]
  7. PR值贡献概率矩阵:
  8. [[0.0 0.0 0.0 0.0 1.0]
  9. [0.3333333333333333 0.0 0.0 0.0 0.0]
  10. [0.3333333333333333 0.0 0.0 0.0 0.0]
  11. [0.3333333333333333 0.5 0.0 0.0 0.0]
  12. [0.0 0.5 1.0 1.0 0.0]]
  13. 初始化的PR值表: [[ 0.2]
  14. [ 0.2]
  15. [ 0.2]
  16. [ 0.2]
  17. [ 0.2]]
  18. 迭代次数:29, succeed PR:
  19. [[0.2962595101978549]
  20. [0.11393416086464467]
  21. [0.11393416086464467]
  22. [0.16239748970660772]
  23. [0.31347467836624976]]
  24. 最终的PR值:
  25. [[0.2962595101978549]
  26. [0.11393416086464467]
  27. [0.11393416086464467]
  28. [0.16239748970660772]
  29. [0.31347467836624976]]

PageRank算法原理与Python实现的更多相关文章

  1. PageRank算法原理及实现

    PageRank算法原理介绍 PageRank算法是google的网页排序算法,在<The Top Ten Algorithms in Data Mining>一书中第6章有介绍.大致原理 ...

  2. 深入学习主成分分析(PCA)算法原理(Python实现)

    一:引入问题 首先看一个表格,下表是某些学生的语文,数学,物理,化学成绩统计: 首先,假设这些科目成绩不相关,也就是说某一科目考多少分与其他科目没有关系,那么如何判断三个学生的优秀程度呢?首先我们一眼 ...

  3. softmax分类算法原理(用python实现)

    逻辑回归神经网络实现手写数字识别 如果更习惯看Jupyter的形式,请戳Gitthub_逻辑回归softmax神经网络实现手写数字识别.ipynb 1 - 导入模块 import numpy as n ...

  4. KNN算法原理(python代码实现)

    kNN(k-nearest neighbor algorithm)算法的核心思想是如果一个样本在特征空间中的k个最相邻的样本中的大多数属于某一个类别,则该样本也属于这个类别,并具有这个类别上样本的特性 ...

  5. (数据科学学习手札13)K-medoids聚类算法原理简介&Python与R的实现

    前几篇我们较为详细地介绍了K-means聚类法的实现方法和具体实战,这种方法虽然快速高效,是大规模数据聚类分析中首选的方法,但是它也有一些短板,比如在数据集中有脏数据时,由于其对每一个类的准则函数为平 ...

  6. 【机器学习】:Kmeans均值聚类算法原理(附带Python代码实现)

    这个算法中文名为k均值聚类算法,首先我们在二维的特殊条件下讨论其实现的过程,方便大家理解. 第一步.随机生成质心 由于这是一个无监督学习的算法,因此我们首先在一个二维的坐标轴下随机给定一堆点,并随即给 ...

  7. 【机器学习实战学习笔记(1-1)】k-近邻算法原理及python实现

    笔者本人是个初入机器学习的小白,主要是想把学习过程中的大概知识和自己的一些经验写下来跟大家分享,也可以加强自己的记忆,有不足的地方还望小伙伴们批评指正,点赞评论走起来~ 文章目录 1.k-近邻算法概述 ...

  8. PageRank算法实现

    基本原理 在互联网上,如果一个网页被很多其他网页所链接,说明它受到普遍的承认和信赖,那么它的排名就高.这就是PageRank的核心思想. 引用来自<数学之美>的简单例子: 网页Y的排名应该 ...

  9. PageRank 算法-Google 如何给网页排名

    公号:码农充电站pro 主页:https://codeshellme.github.io 在互联网早期,随着网络上的网页逐渐增多,如何从海量网页中检索出我们想要的页面,变得非常的重要. 当时著名的雅虎 ...

随机推荐

  1. ArcGIS 生成等值线图

    1.打开ArcCatalog,准备工作(1)菜单:Customize -> Extensions...,在打开的对话框中把里面的东西都勾上.实际要用的应该是GeoStatistical Anal ...

  2. 【Java】SpringBoot-Ajax-Json:Content type 'application/x-www-form-urlencoded;charset=UTF-8' not supported for @RequestBody XXX

    1.重新组装数据 var params=JSON.stringify({"userword":XXXXX,"password":"XXXXX" ...

  3. wordpress默认css样式class和id集合

    你是否想过如何设计WordPress主题的不同元素?每个主题都不一样,但是有一些CSS的class和id是由WordPress生成的.我们将逐一介绍一些最重要的默认WordPress样式,方便初学者快 ...

  4. Java检查异常、非检查异常、运行时异常、非运行时异常的区别

    Java把所有的非正常情况分为两种:异常(Exception)和错误(Error),它们都继承Throwable父类. Java的异常(Exception和Error)分为检查异常和非检查的异常. 其 ...

  5. windows10家庭版升级专业版/企业版

    以防万一,还是把Windows10家庭版的密钥保存下来. 一.保留原密钥 1. Win+R,输入regedit 2. 进入目录 HKEY_LOCAL_MACHINE\SOFTWARE\Microsof ...

  6. 开发(二) ardunio批量固件上传地址

    https://blog.csdn.net/Naisu_kun/article/details/84958561 批量烧录固件到模块中上面讲了如何编写上传程序,接下来讲讲如何量产.相比<Ardu ...

  7. JS的ES6的async

    1.async概念: 真在意义上解决异步回调函数的问题(由于promise的then方法中还是使用回调函数,而async中await并没有使用回调函数真正意义上解决回调函数),同步流程表达异步操作. ...

  8. 再见Spring Boot 1.x

    记得很早很早之前有过一次面试,面试前端说自己喜欢JavaScript,然后面试官问,你知道当前JavaScript最新标准和规范吗?我无言以对,因为平时没有关注认真对待这些信息,然后就没有然后了. 或 ...

  9. Spring Could Stream 基本用法

    Spring Cloud Stream是一个建立在Spring Boot和Spring Integration之上的框架,有助于创建事件驱动或消息驱动的微服务. 通过它可以更方便的访问消息服务,如消费 ...

  10. AtCoder Regular Contest 069 F Flags 二分,2-sat,线段树优化建图

    AtCoder Regular Contest 069 F Flags 二分,2-sat,线段树优化建图 链接 AtCoder 大意 在数轴上放上n个点,点i可能的位置有\(x_i\)或者\(y_i\ ...