PageRank算法实现
- 迭代法实现大规模PageRank,网页数量不低于10000。解答在1.1 迭代法计算PageRank
- 代数法求小规模PageRank的稳态解,网页数量为5。解答在2.2 修正后PageRank的代数法计算
- 附加分,构造不存在稳态的情况,设计方法变为有稳态的情况。解答在2 修正的PageRank 的定义与计算
问题背景
值得一提的是,虽然 PageRank 算法经常被用于搜索引擎中,但是网络节点重要性分析的重要性对于很多领域都是非常重要的。
基本概念
- 马尔可夫性质(Markov property):当一个随机过程在给定现在状态及所有过去状态情况下,其未来状态的条件概率分布仅依赖于当前状态;换句话说,在给定现在状态时,它与过去状态(即该过程的历史路径)是条件独立的。也就是说,系统的状态只与最邻近的上一个状态有关。
P ( x n = x n ∣ x n − 1 = x n − 1 , x n − 2 = x n − 2 , . . . x 0 = x 0 ) = P ( x n = x n ∣ x n − 1 = x n − 1 ) P(x_n=x_n\mid x_{n-1}=x_{n-1}, x_{n-2}=x_{n-2},...x_0=x_0)=P(x_n=x_n\mid x_{n-1}=x_{n-1}) P(xn=xn∣xn−1=xn−1,xn−2=xn−2,...x0=x0)=P(xn=xn∣xn−1=xn−1)
-
马尔可夫链:具有马尔可夫性质的离散时间的链。
-
周期性: p i i ( n ) p_{ii}^{(n)} pii(n)表示在有向图中,经过 n n n个边之后从节点 i i i到节点 i i i的概率。记 d i d_i di是数集 { n ∣ p i i ( n ) > 0 } \{n\mid p_{ii}^{(n)}>0\} {n∣pii(n)>0}的最大公约数,如果 d i = 1 d_i=1 di=1则是非周期,如果 d i > 1 d_i>1 di>1则为周期的,且周期为 d i d_i di。
-
随机游走模型:给定一个含有 n n n 个结点的有向图,在有向图上定义随机游走模型,即一阶马尔可夫链,其中结点表示状态,有向边表示状态之间的转移,假设从一个结点到通过有向边相连的所有结点的转移概率相等。
转移矩阵 M M M :是一个 n n n 阶矩阵 M = [ m i j ] n × n M=[m_{ij}]_{n\times n} M=[mij]n×n。其中 m i j m_{ij} mij 的意义是从节点 j j j到节点 i i i的概率。
**状态分布矩阵 R t R_t Rt **:某个时刻 t t t 访问各个节点的概率分布,其中在$ t+1 $时刻的状态分布矩阵 R t + 1 R_{t+1} Rt+1 是
R t + 1 = M R t R_{t+1}=MR_t Rt+1=MRt
1 PageRank的基本定义
令
u
u
u为一个网页,
N
(
v
)
N(v)
N(v)表示网页
v
v
v向外链接数目,
B
(
u
)
B(u)
B(u)表示连接到网页
u
u
u的网页集合,
R
(
u
)
R(u)
R(u)表示网页
u
u
u的PageRank值,
C
C
C为规范因子,作用是保证所有网页的PageRank总和为常数。
R
(
u
)
=
c
∑
v
∈
B
(
u
)
R
(
v
)
/
N
(
v
)
R(u)=c\sum_{v\in B(u)}{R(v)/N(v)}
R(u)=cv∈B(u)∑R(v)/N(v)
值的一提的是, PageRank 的基本定义是理想化的情况,即要求马尔可夫链不可约且非周期,只有满足这个条件根据马尔可夫平稳分布定理,才会有当时间趋于无穷时状态分布收敛于唯一的平稳分布。
至于不符合上述的限制条件的马尔可夫链求解 PageRank 见本文 2 修正的PageRank 的定义与计算。
1.1 迭代法计算PageRank
1.1.1 基本思路
假设 S S S为整个网页的总和,因为所有网页的 PageRank 值开始都是未知的,所以我们进行平均分配,给每个网页的 PageRank 都赋值 1 / S 1/S 1/S,再根据上式反复迭代计算,直到计算得到的 PageRank 值收敛于一个相对固定的数。也就是说,计算出的所有网页的重要程度趋于稳定,此时停止运算。
即极限
lim
t
→
+
∞
M
t
R
0
=
R
\lim_{t \to +\infty}{M^tR_0}=R
t→+∞limMtR0=R
存在。$ R $就是我们求取的 PageRank 值。
1.1.2 代码实现
# 运行环境:
# macOS 12.3.1
# PyCharm 2021.3.3 (Community Edition)
# Python 3.7
import numpy as np
import random
M = np.zeros((10000, 10000)) # 随机生成10000*10000的数据(可能含有自回路)
for i in range(len(M[0])):
for j in range(len(M[0])):
if i > 100:
if random.random()>0.5:
M[i, j] = 1
else:
M[i, j] = 0
else:
if random.random()>0.2:
M[i, j] = 1
else:
M[i, j] = 0
for i in range(len(M[0])): # 将邻接矩阵转化为转移矩阵
sum_i = np.sum(M[:, i])
for j in range(len(M[0])):
M[j, i] = M[j, i] / sum_i
R = np.ones((len(M[0]), 1)) * (1/len(M[0]))
alpha = 0.85 #
R_1 = np.zeros((len(M[0]), len(M[0])))
e = 100000 # 初始化误差为100000
count = 0 # 记录迭代次数
while e > 0.00000000000001 or count < 1000: # 限制两个迭代条件,即迭代次数和误差大小
# R_1 = np.dot(M, R)*alpha + (1-alpha)/len(M[0]) # 修正的pageRank
R_1 = np.dot(M, R) # 基本的pageRank
e = R - R_1
e = np.max(np.abs(e))
R = R_1
count += 1
print(f'iteration {count}: {e}')
print(f'final :{R}')
2 修正的PageRank 的定义与计算
在之前的定义中就已经提及,先前定义的 PageRank 具有一定的局限性(对于不存在稳态情况无法计算),主要体现在PageRank 值沉淀现象。
2.1 修正的PageRank 的定义
所以引入衰减系数(damping factor) $ \alpha (0<\alpha<1)$,修正后的PageRank定义为:
R
(
u
)
=
α
∑
v
∈
B
(
u
)
R
(
v
)
/
N
(
v
)
+
(
1
−
α
)
R(u)=\alpha \sum_{v\in B(u)}{R(v)/N(v)} + (1-\alpha)
R(u)=αv∈B(u)∑R(v)/N(v)+(1−α)
2.2 修正后PageRank的代数法计算
修正后,PageRank 的平稳分布满足:
R
=
α
M
R
+
1
−
α
n
E
R=\alpha MR + \frac {1-\alpha}{n}E
R=αMR+n1−αE
因此有:
R
=
(
E
−
α
M
)
−
1
1
−
α
n
E
R=(E-\alpha M)^{-1}\frac{1-\alpha}{n}E
R=(E−αM)−1n1−αE
2.2.1 代码实现
# 运行环境:
# macOS 12.3.1
# PyCharm 2021.3.3 (Community Edition)
# Python 3.7
import numpy as np
import random
M = np.zeros((5, 5))
for i in range(len(M[0])):
for j in range(len(M[0])):
if i > 2:
if random.random()>0.5:
M[i, j] = 1
else:
M[i, j] = 0
else:
if random.random()>0.2:
M[i, j] = 1
else:
M[i, j] = 0
for i in range(len(M[0])): # 将邻接矩阵转化为转移矩阵
sum_i = np.sum(M[:, i])
for j in range(len(M[0])):
M[j, i] = M[j, i] / sum_i
alpha = 0.85
A = alpha*M + (1-alpha)/len(M[0])*np.ones((len(M[0]), len(M[0])))
E = np.identity(len(M[0]))
B = np.ones(len(M[0]))
res = (1-alpha)/len(M[0])*np.linalg.inv(E-alpha*M)
res = np.dot(res, np.transpose(B))
print(f'final :{res}')
2.3 修正后的PageRank的迭代法计算
只需要将 1.1.2 代码实现 中的
R_1 = np.dot(M, R)*alpha + (1-alpha)/len(M[0]) # 修正的pageRank
取消注释R_1 = np.dot(M, R) # 基本的pageRank
注释即可
在此不再赘述。
参考文献
[1]曹军.Google的PageRank技术剖析[J].情报杂志,2002(10):15-18.
[2]黄德才,戚华春.PageRank算法研究[J].计算机工程,2006(04):145-146+162.