当前位置:   article > 正文

PageRank算法原理及代码_pagerank算法代码

pagerank算法代码

本文内容出自帅器学习的课程内容,讲得原理清晰,概念深入,链接: PANKRANK算法视频

另有一篇知乎文章,PAGERANK讲得系统透彻,链接在此:关键词提取和摘要算法TextRank详解与实战

PAGERANK算法是一种网页排名算法,其基本思路有两条:

  • 链接数量。一个网页被越多的其他网页链接,说明这个网页很重要。
  • 链接质量。一个网页被一个越高权值的网页链接,也能表明这个网页越重要。

1、课程导论

 

 由A出链到其他节点,即由A可以发射到B  C   
    
    
    
    
    
    
    
 ABCD
A0001
B1000
C1110
D0110

 

 

经过反复研究,这个最终公式是有问题的,应该改为

PR(a)=\beta *(M+a^{T}*\frac{e}{n}) *V+(1-\beta)*\frac{ee^{T}}{n} 

2、代码实践

俗话说实践出真知,听课听懂了,结果实践的时候折腾了一天才弄明白,因为计算pagerank目前已经有成熟的算法,我根据networkx和pygraph现成的算法去验证自己写的是否有问题。

问题,目前有4个网页A B C D

入链和出链关系如下图,那么这4个网页的pagerank是多少呢?

2.1 自写算法

  1. import numpy as np
  2. p = 0.85 #引入浏览当前网页的概率为p,假设p=0.8
  3. a = np.array([[1,0,0,0],
  4. [0,0,0,1],
  5. [0,0,0,1],
  6. [0,1,0,0]],dtype = float) #dtype指定为float
  7. length=a.shape[1] #网页数量
  8. #构造转移矩阵
  9. b = np.transpose(a) #b为a的转置矩阵
  10. m = np.zeros((a.shape),dtype = float)
  11. for i in range(a.shape[0]):
  12. for j in range(a.shape[1]):
  13. #如果一个节点没有任何出链,Dead Ends
  14. if b[j].sum()==0:
  15. b[j]=b[j]+np.array([1/length]*length)
  16. m[i][j] = a[i][j] / (b[j].sum()) #完成初始化分配
  17. #pr值得初始化
  18. v = np.zeros((m.shape[0],1),dtype = float) #构造一个存放pr值得矩阵
  19. for i in range(m.shape[0]):
  20. v[i] = float(1)/m.shape[0]
  21. count=0
  22. ee=np.array([[1/length]*length]).reshape(length,-1)
  23. # 循环100次计算pageRank值
  24. for i in range(100):
  25. # 解决spider traps问题,spider traps会导致网站权重向一个节点偏移,将转移矩阵加上打开其他网页的概率1-p
  26. v = p*np.dot(m,v) + (1-p)*ee
  27. count+=1
  28. print("第{}次迭代".format(count))
  29. #pageRank值
  30. print(v)

2.2 networkx算法

  1. import networkx as nx
  2. import matplotlib.pyplot as plt
  3. # 创建有向图
  4. G = nx.DiGraph()
  5. # 有向图之间边的关系
  6. edges = [("A", "A"), ("B", "D"), ("D", "B"), ("D", "C")]
  7. for edge in edges:
  8. G.add_edge(edge[0], edge[1])
  9. nx.draw(G,with_labels=True)
  10. plt.show()
  11. pagerank_list = nx.pagerank(G, alpha=0.85)
  12. print("pagerank值是:\n", pagerank_list)

 2.3 pygraph算法

  1. from pygraph.classes.digraph import digraph
  2. dg = digraph()
  3. dg.add_nodes(["A", "B", "C", "D"])
  4. dg.add_edge(("A", "A"))
  5. dg.add_edge(("B", "D"))
  6. dg.add_edge(("D", "B"))
  7. dg.add_edge(("D", "C"))
  8. damping_factor = 0.85 # 阻尼系数,即α
  9. max_iterations = 100 # 最大迭代次数
  10. min_delta = 0.00001 # 确定迭代是否结束的参数,即ϵ
  11. graph = dg
  12. for node in graph.nodes():
  13. if len(graph.neighbors(node)) == 0:
  14. for node2 in graph.nodes():
  15. print("node:",node,"node2:",node2)
  16. digraph.add_edge(graph, (node, node2))
  17. print(graph)
  18. print("-"*5)
  19. print("="*30)
  20. nodes = graph.nodes()
  21. graph_size = len(nodes)
  22. page_rank = dict.fromkeys(nodes, 1.0 / graph_size) # 给每个节点赋予初始的PR值
  23. damping_value = (1.0 - damping_factor) / graph_size # 公式中的(1−α)/N部分
  24. flag = False
  25. for i in range(max_iterations):
  26. change = 0
  27. for node in nodes:
  28. rank = 0
  29. for incident_page in graph.incidents(node): # 遍历所有“入射”的页面
  30. rank += damping_factor * (page_rank[incident_page] / len(graph.neighbors(incident_page)))
  31. rank += damping_value
  32. change += abs(page_rank[node] - rank) # 绝对值
  33. page_rank[node] = rank
  34. if change < min_delta:
  35. flag = True
  36. break
  37. if flag:
  38. print("finished in %s iterations!" % node)
  39. else:
  40. print("finished out of 100 iterations!")
  41. print(page_rank)

3、对比

  1. 自写算法结果:
  2. [[0.47534884]
  3. [0.15906977]
  4. [0.15906977]
  5. [0.20651163]]
  6. nx算法结果:
  7. {'A': 0.47534154833093023, 'B': 0.15907194271825495, 'C': 0.15907194271825495, 'D': 0.20651456623255982}
  8. pygraph结果:
  9. {'A': 0.47529602196443255, 'B': 0.1590697675524163, 'C': 0.1590697675524163, 'D': 0.20651162802444234}

自此,我们的理论和实践初级入门就可以了!

4、应用

pagerank既可以用在网页质量的排名,也可以应用到网状节点类的各种问题,比如社交网络、各城市资本流向,以及改进后的TextRank,本文应用从希拉里用私人邮箱处理公务成为丑闻 事件为切入点,理解利用pagerank计算节点度量性。

  1. # -*- coding: utf-8 -*-
  2. # 用 PageRank 挖掘希拉里邮件中的重要任务关系
  3. import pandas as pd
  4. import networkx as nx
  5. import numpy as np
  6. from collections import defaultdict
  7. import matplotlib.pyplot as plt
  8. import os
  9. os.chdir("D:/pagerank/data/")
  10. # 数据加载
  11. emails = pd.read_csv("Emails.csv")
  12. # 读取别名文件
  13. file = pd.read_csv("Aliases.csv")
  14. aliases = {}
  15. for index, row in file.iterrows():
  16. aliases[row['Alias']] = row['PersonId']
  17. # 读取人名文件
  18. file = pd.read_csv("Persons.csv")
  19. persons = {}
  20. for index, row in file.iterrows():
  21. persons[row['Id']] = row['Name']
  22. # 针对别名进行转换
  23. def unify_name(name):
  24. # 姓名统一小写
  25. name = str(name).lower()
  26. # 去掉, 和 @后面的内容
  27. name = name.replace(",","").split("@")[0]
  28. # 别名转换
  29. if name in aliases.keys():
  30. return persons[aliases[name]]
  31. return name
  32. # 画网络图
  33. def show_graph(graph, layout='spring_layout'):
  34. # 使用 Spring Layout 布局,类似中心放射状
  35. if layout == 'circular_layout':
  36. positions=nx.circular_layout(graph)
  37. else:
  38. positions=nx.spring_layout(graph)
  39. # 设置网络图中的节点大小,大小与 pagerank 值相关,因为 pagerank 值很小所以需要 *20000
  40. nodesize = [x['pagerank']*20000 for v,x in graph.nodes(data=True)]
  41. # 设置网络图中的边长度
  42. edgesize = [np.sqrt(e[2]['weight']) for e in graph.edges(data=True)]
  43. # 绘制节点
  44. nx.draw_networkx_nodes(graph, positions, node_size=nodesize, alpha=0.4)
  45. # 绘制边
  46. nx.draw_networkx_edges(graph, positions, edge_size=edgesize, alpha=0.2)
  47. # 绘制节点的 label
  48. nx.draw_networkx_labels(graph, positions, font_size=10)
  49. # 输出希拉里邮件中的所有人物关系图
  50. plt.show()
  51. # 将寄件人和收件人的姓名进行规范化
  52. emails.MetadataFrom = emails.MetadataFrom.apply(unify_name)
  53. emails.MetadataTo = emails.MetadataTo.apply(unify_name)
  54. # 设置遍的权重等于发邮件的次数
  55. edges_weights_temp = defaultdict(list) #defaultdict当字典里的Key不存在时,返回默认值[]
  56. for row in zip(emails.MetadataFrom, emails.MetadataTo, emails.RawText):
  57. temp = (row[0], row[1])
  58. if temp not in edges_weights_temp:
  59. edges_weights_temp[temp] = 1
  60. else:
  61. edges_weights_temp[temp] = edges_weights_temp[temp] + 1
  62. # 转化格式 (from, to), weight => from, to, weight
  63. edges_weights = [(key[0], key[1], val) for key, val in edges_weights_temp.items()]
  64. # 创建一个有向图
  65. graph = nx.DiGraph()
  66. # 设置有向图中的路径及权重 (from, to, weight) add_weighted_edges_fromu、v、w 分别代表起点、终点和权重。
  67. graph.add_weighted_edges_from(edges_weights)
  68. # 计算每个节点(人)的 PR 值,并作为节点的 pagerank 属性
  69. pagerank = nx.pagerank(graph)
  70. # 将 pagerank 数值作为节点的属性
  71. nx.set_node_attributes(graph, name = 'pagerank', values=pagerank)
  72. # 画网络图
  73. show_graph(graph)
  74. # 将完整的图谱进行精简
  75. # 设置 PR 值的阈值,筛选大于阈值的重要核心节点
  76. pagerank_threshold = 0.005
  77. # 复制一份计算好的网络图
  78. small_graph = graph.copy()
  79. # 剪掉 PR 值小于 pagerank_threshold 的节点
  80. for n, p_rank in graph.nodes(data=True):
  81. if p_rank['pagerank'] < pagerank_threshold:
  82. small_graph.remove_node(n)
  83. # 画网络图,采用circular_layout布局让筛选出来的点组成一个圆
  84. show_graph(small_graph, 'circular_layout')

 

 

参考链接

PageRank算法与TextRank算法详解:点此链接

希拉里原始数据:点此链接

TextRank算法的基本原理及textrank4zh使用实例:点此链接

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/煮酒与君饮/article/detail/773905
推荐阅读
相关标签
  

闽ICP备14008679号