PageRank算法的Python实现

五个节点的链接关系如下图:

PageRank算法的Python实现_第1张图片

代码:

# -*- coding: utf-8 -*-
"""
Created on Sat Sep 12 10:36:10 2020

@author: Administrator
"""

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("第%s次迭代" % (i + 1))
            print(page_rank)

            if change < self.min_delta:
                flag = True
                break
        if flag:
            print("符合终止条件,迭代结束!")
        else:
            print("已经完成了100次迭代!")
        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("最终的PR值是\n", page_ranks)

解析:page_rank(self)的作用是避免出现悬空节点(指没有出度的节点),否则不断迭代,网页整体的PageRank值会降低为0。

拓展:在PageRank的原理中,定义了一个矩阵A(S是链接矩阵)->原理详情

我们用一个列向量P来表示n个网页的PageRank值,给定初值P0就可以通过若干次迭代得到Pn。满足公式方程组的解P*就是最终的全局PageRank值列向量。

但是,要存在这样的解,需要转移矩阵A满足三个条件:

  • 随机矩阵
  • 不可约矩阵
  • 非周期性矩阵

随机矩阵理解为避免出现悬空节点(指没有出度的节点),否则不断迭代,网页整体的PageRank值会降低为0。

  • 解决方式:将矩阵全为0的一行元素用1/n代替,即我们是有一定概率访问其他网页的。

不可约矩阵就是矩阵A对应的有向图是强连接图,每个节点都存在链接,即我们无论在访问哪个网页,都有概率访问别的网页。

  • 解决方式:以α的概率选择一个链出链接继续浏览,1-α概率不点击链接,随机选择一个网页进行浏览。

参考:https://www.cnblogs.com/chenshaowei/p/12269305.html

你可能感兴趣的:(算法,python,机器学习,深度学习,算法,PageRank)