PageRank算法
标签(空格分隔): 图模型
搜索引擎根据关键字匹配搜索到海量的相关网页,但这些网页并不都是我们需要的,其中存在大量的垃圾网页。那么,如何找到我们需要的网页呢?pagerank算法是对搜索到的网页进行排名的强大算法。
算法来源
PageRank算法来源于文献检索系统,网络上海量的网页存在链接与被链接的关系,与各种文献引用与被引用的关系构成的网络类似。在文献引用系统中,被引用最多的文章最有价值,同理,被链接到的数量越大的网页越重要。
PageRank
的一个直观描述:如果某个网页的反向链接(如果
A
能跳转到
PR值的计算
如果u表示当前网页,
F u
表示能从u链接跳转到的所有下一级网页的集合,
B u
表示能跳转到u的所有网页的集合。
N u =|F u |
是u跳转到的所有网页的个数。c是一个标准化的因子。我们通过如下公式计算网页u的PR值:
数学建模
假设n是Internet中所有可访问网页的数目,此数值非常大,在2010年已接近100亿,定义 n×n 的网页链接矩阵 G=(g ij )∈R n×n ,若从网页j有一个链接到网页i,则 g ij =1 ,否则 g ij =0 。矩阵G有如下特点:
- G矩阵是一个大规模的稀疏矩阵
- 第j列非零元素的位置表示从网页j链接出去的所有网页;
- 第i行非零元素的位置表示所有链接到网页i的网页;
- G中非零元素的数目为整个Internet中存在超链接的个数;
- G矩阵元素之和 r i =∑ j g ij ,他表示第i个网页的“入度”。
- G矩阵列元素之和 c j =∑ i g ij ,他表示第j个网页的“出度”
要计算PageRank,可假设一个随机冲浪过程,即每次看完当前网页后有两种选择:
- 在当前页中随机选一个超链接进入下一个网页(由于随机选择,所以当前页链接的所有网页的概率相同,即如果当前页的出度是c,那么进入每一个网页的概率都是1/c);
- 随机的开一个新的网页。新开的网页概率为1/n
这在数学上称为马尔可夫过程。如这样的冲浪一直进行下去,某个网页被访问到的极限概率就是它的PageRank。
设p为选择当前网页上链接的概率(比如,p=0.85),则1-p为不选当前网页的链接而随机打开一个网页的概率。若当前网页是网页j,则计算下一步浏览到达网页i的概率,即网页j到网页i的转移概率,分两种可能性:
- 若网页i在网页j的链接上,即点击网页j上的超链接可以跳转到网页i,其概率为 p×1/c j +(1−p)×1/n ;
- 若网页i不在网页j的链接上,其概率为 (1−p)×1/n
网页i是否在网页j的链接上由 g ij 决定,网页j跳转到i的转移概率为:
任意两个网页之间的转移概率形成了一个转移概率矩阵
A=(a ij ) n×n
。假设矩阵D为各个网页出度的倒数(若没有出度,设为1)构成的n介对角阵,e为全是1的n维向量,则
设
x (k) ,i=1,2,⋯,n
表示某时刻k浏览网页i的概率(
∑x (k) i =1
),向量
x (k)
表示当前k时刻浏览各网页的概率分布,那么下一时刻浏览到网页i的概率为
∑ n j=1 a ij x (k) j
,此时浏览各个网页的概率分布为
x (k+1) =Ax (k)
。
当这个过程无限进行下去,达到极限情况,即网页访问概率
x (k)
收敛到一个极限值,这个极限向量x为各个网页的PageRank,他满足Ax=x, 且
∑ n x i =1 x i =1
。最后得到一个等式
Ax=x
, 实际上就是求矩阵
A
的特征值为1的特征向量。我们可以用求特征值的方法求解。
圆盘定理证明A的主特征值为1
设
Gersgorin圆盘定理 设
A=(a ii )∈c n×n
,则
(1)A的任一特征值
λ∈G(A)=⋃ n i=1 G i
,每个
G i
称为A的Gersgorin圆盘,简称盖式圆盘。
(2)若A的n个盖式圆盘中有k个的并形成一个连通区域,并且与其余的n-k的个圆盘都不相交,则在此连通区域中恰有A的k个特征值。特别的,孤立的盖式圆盘内有且仅有一个特征值。
由于
A=pGD+1−pn ee T
,矩阵GD的每一列的和为1.转移概率矩阵的形式为:
其中, c j 为第j个网页的出度, p 表示选择当前网页上链接的概率。
根据圆盘定理,矩阵
PageRank计算
#!/usr/bin/env python3
# -*- encoding: utf-8 -*-
import numpy as np
a = np.array([[0, 1, 1, 0],
[1, 0, 0, 1],
[1, 0, 0, 1],
[1, 1, 0, 0]], dtype=float) # dtype指定为float
# 构造转移矩阵
def graphMove(a):
c_j = np.sum(a, axis=0)
c = a/c_j
print(c, "\n====================================================")
return c
# pr值得初始化
def firstPr(c):
n = c.shape[0]
pr = np.array([[1/n] for i in range(n)], dtype=float)
print(pr, "\n===================================================")
return pr
def pageRank(p, m, v):
'''
迭代更新pagerank值,直到停止
'''
# 判断pr矩阵是否收敛,(v == p*dot(m,v) + (1-p)*v).all()判断前后的pr矩阵是否相等,若相等则停止循环
while ((v == p * np.dot(m, v) + (
1 - p) * v).all() == False):
# print v
v = p * np.dot(m, v) + (1 - p) * v
# print (v == p*dot(m,v) + (1-p)*v).all()
return v
def pageRank_mi(p, M):
'''
求概率转移矩阵A的特征值为1的特征向量,单位化。
'''
A = p * M + (1 - p) / M.shape[0]
b1, b2 = np.linalg.eig(A)
v = b2[:, b1.tolist().index(1.0)]
return v / np.sum(v)
if __name__ == "__main__":
p = 0.8 # 引入浏览当前网页的概率为p,假设p=0.8
M = graphMove(a)
pr = firstPr(M)
print('迭代法: ', pageRank(p, M, pr)) # 计算pr值
print('特征值法: ', pageRank_mi(p, M))