一、基本介绍
PageRank算法的基本想法是在有向图上定义一个随机游走模型,即一阶马尔可夫链,描述随机游走者沿着有向图随机访问各个结点的行为。在一定条件下,极限情况访问每个结点的概率收敛到平稳分布,各结点的平稳概率值就是其PageRank值,表示结点的重要度。
PageRank是递归定义的,PageRank的计算可以通过迭代算法进行。
二、实验内容
PageRank算法的核心部分可以从一个有向图开始。最典型的方法是根据有向图构造邻接矩阵来进行处理。邻接矩阵A=(a[i,j])中的元素a[i,j] (∈[0,1])表示从页面j指向页面i的概率。
基本的PageRank算法在计算等级值时,每个页面都将自己的等级值平均地分配给其引用的页面节点。假设页面的等级值为1,该页面上共有n个超链接,分配给每个超链接页面的等级值就是1/n,那么就可以理解为该页面以1/n的概率跳转到任意一个其所引用的页面上。
一般地,把邻接矩阵A转换成所谓的转移概率矩阵M来实现PageRank算法:
M=(1-d)*Q+d*A
其中,Q是一个常量矩阵,最常用的是Q=(q[i,j]),q[i,j]=1/n。
转移概率矩阵M可以作为一个向量变换矩阵来帮助完成页面等级值向量R的迭代计算:
R[i+1]=M*R[i]
页面之间的超链接分析通常基于以下假设:
(1)若页面A上存在指向页面B的超链接,就认为页面A对页面B进行了一次参考引用;
(2)一个页面被越多的其他页面指向,越能说明这个页面等级越高;
(3)每个页面都有一个衡量其重要性的参数值(等级值),并且会将这一参数值平均地分配给它指向的全部页面。
三、算法伪代码
四、算法流程图
五、关键源码展示
1、导入数据
2、计算移转概率矩阵
3、计算页面等级值向量
4、输出页面等级值向量
六、 完整代码与数据集
1、完整代码
N = 4
d = 0.85
delt = 0.1
def loadData():
with open("PageRank.txt", "r") as f:
fline = f.readlines()
matrix = []
buffer = []
for item in fline[0:]:
line = item.strip().split(',')
# print(line)
for i in range(len(line)):
if '/' in line[i]:
buffer.append(float(line[i].split('/')[0]) / float(line[i].split('/')[1]))
else:
buffer.append(float(line[i]))
matrix.append(buffer.copy())
buffer.clear()
# print(matrix)
return matrix
# 矩阵相加
def matrix_add(A, B):
result = []
for i in range(len(A)):
result.append([])
for j in range(len(A[i])):
result[i].append(A[i][j] + B[i][j])
return result
# 矩阵相乘
def matrix_multi(A, B):
result = [[0 for _ in range(len(B[0]))] for _ in range(len(A))]
for i in range(len(A)):
for j in range(len(B[0])):
for k in range(len(B)):
result[i][j] += A[i][k] * B[k][0]
return result
# 根据邻接矩阵求转移概率矩阵
def Transfer_Probability_Matrix(A):
q = [[(1 - d) * (1 / N)] * N for _ in range(N)]
for i in range(len(A)):
for j in range(len(A[0])):
A[i][j] = d * A[i][j]
result = matrix_add(q, A)
return result
# 基于随机冲浪的PageRank算法
def PageRank(M):
r = [[1] * N for _ in range(N)]
New_R = r
R = [0] * N
epsilon = 1
cnt = 1
while epsilon > delt:
r = New_R
New_R = matrix_multi(M, r)
epsilon = 0
# 求解矩阵一阶范数
for i in range(N):
epsilon += abs(New_R[i][0] - r[i][0])
for i in range(len(New_R)):
R[i] = New_R[i][0]
print('R[{}]={}'.format(cnt, R))
if epsilon > delt:
print('ε{}={}>ε={},因此继续迭代...'.format(cnt, epsilon, delt))
else:
print('ε{}={}≤ε={},因此迭代结束'.format(cnt, epsilon, delt))
print()
cnt += 1
def main():
A = loadData()
# A = [[0, 1 / 2, 0, 1 / 2],
# [1 / 3, 0, 0, 1 / 2],
# [1 / 3, 1 / 2, 0, 0],
# [1 / 3, 0, 1, 0]]
M = Transfer_Probability_Matrix(A)
print('M:')
for i in range(len(M)):
print(M[i])
# print('M={}'.format(M))
print()
PageRank(M)
if __name__ == '__main__':
main()
2、数据集
0,1/2,1,0
1/3,0,0,1/2
1/3,0,0,1/2
1/3,1/2,0,0