首页 > 编程语言 >PageRank算法概述与Python实现

PageRank算法概述与Python实现

时间:2024-04-27 15:12:10浏览次数:19  
标签:__ 网页 Python 算法 PageRank np array

PageRank算法是一种用于评估网页重要性的算法。它基于网页之间的链接结构来确定网页的权重和重要性。算法的核心思想是通过迭代计算网页之间的链接关系,以确定每个网页的权重。它将互联网视为一个有向图,其中网页是节点,链接是有向边。算法通过以下方式计算网页的PageRank值:每个网页的初始PageRank值相等,然后通过迭代更新计算,将每个网页的PageRank值传递给链接到它的网页,直到收敛为止。在计算过程中,还引入了阻尼因子,用于模拟用户在浏览网页时的随机跳转行为。这样可以确保算法收敛并得到稳定的结果。PageRank算法是Coogle搜索擎对检索结果的一种排序算法。它的基本思想主要是来自传统文献计量学中的文献引文分析,即一篇文献的质量和重要性可以通过其他文献对其引用的数量和引文质量来衡量,也就是说,一篇文献被其他文献引用越多,并且引用的文献的质量越高,则该文献本身就越重要,它也被广泛应用于其他领域,如网络分析、推荐系统和数据挖掘。

一、PageRank算法思想

PageRank算法是Google创始人提出的一种用于标识网页重要性的方法,它主要用于网页的排序。PR值越高说明网站越重要,因此其排名也越靠前。PageRank算法的核心思想是基于有向图上的随机游走模型,这个模型描述了一个随机游走者如何沿着图的边随机移动,从一个节点访问到另一个节点。在满足某些条件的前提下,这个随机游走过程最终会收敛到一个平稳分布,在这个平稳分布中,每个节点被访问的概率即为其PageRank值,这个值可以被解释为节点的重要性。
PagsRank算法的具体实现可以利用网页所对应图的邻接矩阵来表达超链接关系。首先写出所对应图的邻接矩阵\(W\),为了能将网页的页面等级值平均分配给该网页所链接指向的网页,对\(W\)各个行向量进行归一化处理,得到矩阵\(P\)。矩阵\(P\)称为状态转移概率矩阵,它的各个行向量元素之和为1,\(P^T\)的最大特征值(一定为1)所对应的归一化特征向量即为各顶点的PageRank值。PageRank值的计算步骤如下:

  • 构造有向图\(D=(V,A,W)\),其中\(V=\{v_1,v_2,...,v_N\}\)为顶点集合,每一个网页是的一个顶点,\(A\)为弧的集合,网页间的每一个超链接是图的一条弧,邻接矩阵\(W=(w_{ij})_{N\times N}\)​,如果从网页\(i\)到网页\(j\)有超链接,则\(w_{ij}=1\),否则为0。
  • 记矩阵 \({r_i} = \sum\limits_{j = 1}^N {{w_{ij}}}\)​为第\(i\)行的和,它给出了页面\(i\)的链出链接数目。定义矩阵\(P=(p_{ij})_{N \times N}\)​如下:

    \[p_{ij}=\frac{{{w_{ij}}}}{{{r_i}}} \]

  • \(P^T\)的最大特征值(一定为1)所对应的归一化特征向量即为各顶点的PageRank值。

1.1 示例1

影响力评价问题,见下图给出了6篇文章之间的引用关系,即文章1分别引用了文章2、4、5、6;文章2分别引用了文章4、5、6;等等,试给出6篇文章影响力大小的排序。

网络图 PageRank
import numpy as np
from scipy.sparse.linalg import eigs
import pylab as plt
import sympy as sp

L = [(1,2),(1,4),(1,5),(1,6),(2,4),(2,5),(2,6),(3,1),(3,2),(3,4),(4,5),(4,6),(5,3),(5,6),(6,3)]
w = np.zeros((6, 6))  # 邻接矩阵初始化
for i in range(len(L)):
    w[L[i][0]-1, L[i][1]-1] = 1
r = np.sum(w, axis=1, keepdims=True)
for i in range(len(r)):
    if r[i][0] != 0:
        r[i][0] = sp.Rational(r[i][0] ** -1)

r = np.array(r)
print(r) # 由于0不为分母,先将r成以-1方,避免相除出错。

P = w * r            # 这里利用矩阵广播
print(P)
val, vec = eigs(P.T, 1)
V = vec.real
V = V.flatten()  # 展开成(n,)形式的数组
V = V/V.sum()
print("V=", np.round(V, 4))
plt.bar(range(1, len(w)+1), V, width=0.6, color='b')
plt.show()

1.2 示例2

PageRank算法是图的链接分析的代表性算法,属于图数据上的无监督学习方法。其基本想法是在一个有向图上定义一个随机游走模型,即一阶马尔科夫链,描述随机游走者沿着有向图随机访问各个结点的行为。

网络图 转移概率矩阵
import numpy as np
from fractions import Fraction

np.set_printoptions(formatter={'all': lambda x: str(Fraction(x).limit_denominator())})  # 格式化 保留分数,不至于精度丢失
M = np.array([[0, 1 / 2, 1, 0], [1 / 3, 0, 0, 1 / 2], [1 / 3, 0, 0, 1 / 2], [1 / 3, 1 / 2, 0, 0]])  # 根据有向图得出的转移矩阵
R = np.array([1 / 4, 1 / 4, 1 / 4, 1 / 4]).reshape(4, 1)  # 初始R0

def diedai(M, R):  # 定义一个迭代函数,直至MR=R时,输出R
    count = 0
    while (True):
        R_1 = np.dot(M, R)
        if ((R_1 == R).any()):  # 判断两个数组是否相等
            print(R_1)
            print('迭代次数为:', count)
            break
        else:
            R = np.copy(R_1)
            count += 1

diedai(M, R)

二、算法算例

2.1 示例1

2.2 示例2

假设有4个网页,见下图。他们之间的链接信息如上图所示,A跳转到B、C、D的概率各位1/3,B跳转到A、D的概率为1/2,C跳转到A的概率为1,因此我们可以得到转移矩阵为M。

网络连接图 概率转移矩阵

\[M=\left[\begin{array}{cccc} 0 & 1 / 2 & 1 & 0 \\ 1 / 3 & 0 & 0 & 1 / 2 \\ 1 / 3 & 0 & 0 & 1 / 2 \\ 1 / 3 & 1 / 2 & 0 & 0 \end{array}\right] \]

我们假设 \(A 、 B 、 C 、 D\) 四个页面的初始影响力都是相同的,即:

\[v_0=\left[\begin{array}{l} 1 / 4 \\ 1 / 4 \\ 1 / 4 \\ 1 / 4 \end{array}\right] \]

经过第一次转移后,各页面的影响因子 \(v\{1\}\) 变为:

\[v_1=M v_0=\left[\begin{array}{cccc} 0 & 1 / 2 & 1 & 0 \\ 1 / 3 & 0 & 0 & 1 / 2 \\ 1 / 3 & 0 & 0 & 1 / 2 \\ 1 / 3 & 1 / 2 & 0 & 0 \end{array}\right]\left[\begin{array}{l} 1 / 4 \\ 1 / 4 \\ 1 / 4 \\ 1 / 4 \end{array}\right]=\left[\begin{array}{l} 9 / 24 \\ 5 / 24 \\ 5 / 24 \\ 5 / 24 \end{array}\right] \]

然后我们再用转移矩阵乘以 \(v\{1\}\) 得到 \(v\{2\}\) 结果,直到迭代 \(n\) 次 \(v\{n\}\) 影响因子不在发生变化,可以收玫为 \((0.3333,0.2222,0.2222,0.2222)\) ,也就是对应A、B、C、D四个页面下的PageRank值。考虑到页面可能会自身循环和陷阱问题,可再加一个网页跳转概率 \(p\) ,公式变为 \(v=p^* M^* v+(1-p)^{\star} v\)。

from numpy import *
a = array([[0,1,1,0],[1,0,0,1],[1,0,0,1],[1,1,0,0]],dtype=float)
#构造转移矩阵
def transPre(data):
    b = transpose(data) #把矩阵转置
    c = zeros((a.shape),dtype=float)
    #把所有的元素重新分配
    for i in range(a.shape[0]):
        for j in range(a.shape[1]):
            c[i][j] = data[i][j] / (b[j].sum())
    return c
# print(transPre(a))

def initiPre(c):
    # pr值的初始化
    pr = zeros((c.shape[0],1),dtype=float)
    for i in range(c.shape[0]):
        pr[i] = float(1)/c.shape[0]
    return pr
# print(initiPre(a))

def PageRank(p,m,v):
    #pageRank算法
    #p是网页跳转概率,m是转移矩阵,v是pr值
    while ((v == p*dot(m,v) + (1-p)*v).all() == False):
        v = p*dot(m,v) + (1-p)*v
        # print(v)
        print((v == p*dot(m,v) + (1-p)*v).all())
    return v
if __name__ == '__main__':
    M = transPre(a)
    pr = initiPre(M)
    p = 0.85
    print(PageRank(p,M,pr))

三、pagerank的Python实现

3.1 PageRank基本定义求PageRank值

import numpy as np
def pagerank_basic(M, tol=1e-8, max_iter=1000):
    """使用PageRank的基本定义求解PageRank值
    要求有向图是强联通且非周期性的
    :param M: 转移概率矩阵
    :param tol: 容差
    :param max_iter: 最大迭代次数
    :return: PageRank值(平稳分布)
    """
    n_components = len(M)

    # 初始状态分布:均匀分布
    pr0 = np.array([1 / n_components] * n_components)

    # 迭代寻找平稳状态
    for _ in range(max_iter):
        pr1 = np.dot(M, pr0)
        # 判断迭代更新量是否小于容差
        if np.sum(np.abs(pr0 - pr1)) < tol:
            break
        pr0 = pr1
    return pr0

if __name__ == "__main__":
    np.set_printoptions(precision=2, suppress=True)
    P = np.array([[0, 1 / 2, 1, 0],
                  [1 / 3, 0, 0, 1 / 2],
                  [1 / 3, 0, 0, 1 / 2],
                  [1 / 3, 1 / 2, 0, 0]])
    print(pagerank_basic(P))  # [0.33 0.22 0.22 0.22]

3.2 迭代算法


import numpy as np
def pagerank_1(M, d=0.8, tol=1e-8, max_iter=1000):
    """PageRank的迭代算法
    :param M: 转移概率矩阵
    :param d: 阻尼因子
    :param tol: 容差
    :param max_iter: 最大迭代次数
    :return: PageRank值(平稳分布)
    """
    n_components = len(M)

    # 初始状态分布:均匀分布
    pr0 = np.array([1 / n_components] * n_components)

    # 迭代寻找平稳状态
    for _ in range(max_iter):
        pr1 = d * np.dot(M, pr0) + (1 - d) / n_components

        # 判断迭代更新量是否小于容差
        if np.sum(np.abs(pr0 - pr1)) < tol:
            break
        pr0 = pr1
    return pr0
if __name__ == "__main__":
    np.set_printoptions(precision=2, suppress=True)
    P = np.array([[0, 1 / 2, 0, 0],
                  [1 / 3, 0, 0, 1 / 2],
                  [1 / 3, 0, 1, 1 / 2],
                  [1 / 3, 1 / 2, 0, 0]])
    print(pagerank_1(P))  # [0.1  0.13 0.64 0.13]

3.3 幂法计算

import numpy as np
def pagerank_2(M, d=0.8, tol=1e-8, max_iter=1000):
    """计算一般PageRank的幂法

    :param M: 转移概率矩阵
    :param d: 阻尼因子
    :param tol: 容差
    :param max_iter: 最大迭代次数
    :return: PageRank值(平稳分布)
    """
    n_components = len(M)

    # 选择初始向量x0:均匀分布
    x0 = np.array([1 / n_components] * n_components)
    # 计算有向图的一般转移矩阵A
    A = d * M + (1 - d) / n_components
    # 迭代并规范化结果向量
    for _ in range(max_iter):
        x1 = np.dot(A, x0)
        x1 /= np.max(x1)
        # 判断迭代更新量是否小于容差
        if np.sum(np.abs(x0 - x1)) < tol:
            break
        x0 = x1
    # 对结果进行规范化处理,使其表示概率分布
    x0 /= np.sum(x0)
    return x0

if __name__ == "__main__":
    np.set_printoptions(precision=2, suppress=True)
    P = np.array([[0, 1 / 2, 0, 0],
                  [1 / 3, 0, 0, 1 / 2],
                  [1 / 3, 0, 1, 1 / 2],
                  [1 / 3, 1 / 2, 0, 0]])
    print(pagerank_2(P))  # [0.1  0.13 0.64 0.13]

总结

PageRank算法的应用场合广泛,其中最为人所熟知的是在搜索引擎中的应用。谷歌等顶级搜索引擎的排名算法中都运用了PageRank算法。通过计算每个网页的> PageRank值,搜索引擎能够确定网页的等级,并将其作为搜索结果排序的重要依据。pageRank算法应用如下:

搜索引擎排名:它帮助搜索引擎确定网页在搜索结果中的排名,使得更重要和相关的网页更容易被用户找到。这样,用户在进行搜索时,更有可能得到高质量、相关性强的网页结果。
网络分析:PageRank算法也被用于分析其他类型的网络,如社交网络、引用网络等。通过计算节点的PageRank值,可以识别网络中的重要节点、中心节点和关键节点。
推荐系统:在推荐系统中,PageRank算法可以用来识别用户可能感兴趣的内容或产品。通过分析用户之间的关系和他们对内容的反应,可以为用户推荐最相关的内容。
媒体网站优化:媒体和新闻网站可以使用PageRank算法来优化其内容的布局和链接结构,以提高重要文章和页面的曝光度,并增加用户的点击量和访问量。
数据挖掘:PageRank算法在数据挖掘领域也有广泛应用,例如在社交网络分析、文本分析和推荐系统中。通过分析链接关系,可以发现隐藏在数据中的模式和趋势。
总的来说,PageRank算法不仅是一种用于搜索引擎排名的技术,还是一种通用的网络分析工具,可以在许多领域中发挥作用,帮助人们理解和利用复杂的网络结构。值得注意的是,PageRank算法并非完美无缺。在实际应用中,可能会遇到一些问题和挑战,如垃圾链接、链接欺诈等。这些问题可能会干扰PageRank算法的计算结果,从而影响网页排名的准确性。因此,在使用PageRank算法时,需要采取相应的措施来应对这些问题,确保算法的有效性和准确性。相信通过不断的研究和改进,相信PageRank算法在未来会有更广泛的应用和更好的表现。

参考资料

  1. PageRank 算法 python应用
  2. Python实现PageRank计算
  3. 《统计学习方法》第21章 PageRank 算法(教材全解 + 公式推导 + Python实现)

标签:__,网页,Python,算法,PageRank,np,array
From: https://www.cnblogs.com/haohai9309/p/18161988

相关文章

  • python简介,第一个Python程序
    Python:可以做日常任务,比如自动备份你的MP3;可以做网站,很多著名的网站包括YouTube就是Python写的;可以做网络游戏的后台,很多在线游戏的后台都是Python开发的。Python当然也有不能干的事情,比如写操作系统,这个只能用C语言写;写手机应用,只能用Swift/Objective-C(针对iPhone)和Java(针对Andr......
  • 【知识点】欧几里得算法求最大公约数
    最大公约数所为的最大公约数,是指两个或多个整数共有的约数中最大的那个数。换句话说,它是能同时整除给定的整数的最大整数。例如,对于整数\(12\)和\(18\),它们的公约数有\(1、2、3、6\),其中最大的公约数为6,因此它们的最大公约数为\(6\)。最大公约数通常用符号\(\gcd(a,b)\)......
  • 华为od python
    importsysrows=4cols=4matrix=[[0,1,1,1],[30,30,-1,40],[0,20,20,40],[10,-1,30,40]]offsets=((-1,0),(1,0),(0,-1),(0,1))classNode:def__init__(self,x,y):self.x=xself.y=yself.initial_energy=0......
  • 利用python将沪深300股票历史数据存储在sqlite3
    一、环境准备1、python3中自带了sqlite3参考https://www.runoob.com/sqlite/sqlite-tutorial.html2、在sqlite中建表CREATETABLE[stock]([id]NVARCHAR(48),[name]NVARCHAR(24), [code]NVARCHAR(24),[date]INTEGERNOTNULL,[open]REAL,[close]......
  • 排序算法
    1.直接插入排序:直接插入排序就是把待排序的元素逐个插入到一个已经排好序的有序序列中,直到所有的记录插入完为止,得到一个新的有序序列。实际中我们玩扑克牌时,就用了插入排序的思想voidInsertSort(int*arr,intsize)//直接插入排序{for(inti=0;i<size-1;i+......
  • 目标检测与追踪AI算法模型及边缘计算智能分析网关V4的算法应用
    目标检测与追踪是计算机视觉领域中的一个重要任务,主要用于识别图像或视频中的目标,并跟踪它们的运动轨迹。针对这一任务,有许多先进的AI算法模型,例如:YOLO(YouOnlyLookOnce):一种实时目标检测算法,通过单个神经网络模型实现对图像中多个目标的检测和定位。FasterR-CNN:基于深度学习......
  • 【python】记录一次python发送json数据到go服务端,服务端解析失败问题
    【python】记录一次python发送json数据到go服务端,服务端解析失败问题背景:在做性能测试时,python把采集到的性能数据通过post回传到服务端,服务端用go实现,服务端是将接收的json通过json.Unmarshal反序列化为对应的结构体,但在实现时一直提示数据类型错误的问题问题代码python发送请......
  • python - [11] 日常脚本汇总
    题记部分  一、updatetime更新将脚本放到目标文件夹,运行脚本可将文件夹下所有文件的更新时间都修改为当前时间。importos#指定目录路径directory_path="./"#遍历目录下的所有文件和子目录forroot,dirs,filesinos.walk(directory_path):forfilei......
  • python C++混合编程环境搭建
    一、python环境1.下载python安装包2.安装python(选择下载符号文件和二进制文件)注:多半会报错“Error0x80072f7d:FailedtosendrequesttoURL:……”,因为下载超时导致安装失败解决:1)手动下载core_pdb.msi等文件https://www.python.org/ftp/python/3.8.0/win32/(选择......
  • python读取xml,添加节点
    采用minidom读取,在dom上创建新节点,dom.createElement('item')再将节点挂在对应节点下byCardNo.appendChild(item)将修改后的dom重新写入,建议换一个文件名再测试,避免覆盖defadd(filename):#创建dom文档dom=minidom.parse(filename)root=dom......