PageRank的Page可是认为是网页,表示网页排名,也可以认为是Larry Page(google 产品经理),因为他是这个算法的发明者之一,还是google CEO。PageRank算法计算每一个网页的PageRank值,然后根据这个值的大小对网页的重要性进行排序。
互联网中的网页可以看出是一个有向图,其中网页是结点,如果网页A有链接到网页B,则存在一条有向边A->B,下面是一个简单的示例
根据上图,我们可以得到一个转移概率矩阵。例如用户当前在A网页,那么用户将各以三分之一的概率跳转到B,C,D网页。转移矩阵 M M 如下,每一列的和为1
page | A | B | C | D |
---|---|---|---|---|
A | 0 | 1/2 | 1 | 0 |
B | 1/3 | 0 | 0 | 1/2 |
C | 1/3 | 0 | 0 | 1/2 |
D | 1/3 | 1/2 | 0 | 0 |
初始时,假设上网者在每个网页的概率是相等的,即 1/n 1 / n , 于是初始概率分布就是所有值都为 1/n 1 / n 的nwei维向量 V0 V 0 ,可以通过如下方式进行迭代
V1=MV0=⎡⎣⎢⎢⎢⎢01/31/31/31/2001/2100001/21/20⎤⎦⎥⎥⎥⎥⎡⎣⎢⎢⎢⎢1/41/41/41/4⎤⎦⎥⎥⎥⎥=⎡⎣⎢⎢⎢⎢3/92/92/92/9⎤⎦⎥⎥⎥⎥ V 1 = M V 0 = [ 0 1 / 2 1 0 1 / 3 0 0 1 / 2 1 / 3 0 0 1 / 2 1 / 3 1 / 2 0 0 ] [ 1 / 4 1 / 4 1 / 4 1 / 4 ] = [ 3 / 9 2 / 9 2 / 9 2 / 9 ]
Vi=MVi−1 V i = M V i − 1
不断的迭代计算,直到 |Vi+1−Vi|<ϵ | V i + 1 − V i | < ϵ , Vi V i 不再变化为止。最终会收敛到一个恒定值,得到各个网页访问的概率
上述上网者的行为是一个马尔科夫过程的实例,要满足收敛性,需要具备一个条件:图是强连通的,即从任意网页可以到达其他任意网页
假定上网者在每一步,都可能不想看当前网页了,而是在地址栏输入另外一个地址,而地址栏跳转到各个网页的概率是 1/n 1 / n 。假设上网者每一步查看当前网页的概率是 α α ,从地址栏跳转的概率是 1−α 1 − α 。alpha一般取0.85,迭代公式如下:
Vi+1=αMVi+(1−α)e V i + 1 = α M V i + ( 1 − α ) e
重新计算第一步的迭代如下:
V1=αMV0+(1−α)e=0.85∗⎡⎣⎢⎢⎢⎢01/31/31/31/2001/2100001/21/20⎤⎦⎥⎥⎥⎥⎡⎣⎢⎢⎢⎢1/41/41/41/4⎤⎦⎥⎥⎥⎥+0.15∗⎡⎣⎢⎢⎢⎢1/41/41/41/4⎤⎦⎥⎥⎥⎥=⎡⎣⎢⎢⎢⎢9/6013/6025/6013/60⎤⎦⎥⎥⎥⎥ V 1 = α M V 0 + ( 1 − α ) e = 0.85 ∗ [ 0 1 / 2 1 0 1 / 3 0 0 1 / 2 1 / 3 0 0 1 / 2 1 / 3 1 / 2 0 0 ] [ 1 / 4 1 / 4 1 / 4 1 / 4 ] + 0.15 ∗ [ 1 / 4 1 / 4 1 / 4 1 / 4 ] = [ 9 / 60 13 / 60 25 / 60 13 / 60 ]
迭代计算直至 |Vi+1−Vi|<ϵ | V i + 1 − V i | < ϵ ,可以得到最终结果
大规模稀疏矩阵运算时,在python中使用scipy.sparse_coomatrix比直接使用dense matrix快的多
# coding:utf-8
import pandas as pd
import numpy as np
def PageRank(M, alpha, root):
"""
Personal Rank in matrix formation
:param M: transfer probability matrix
:param index2node: index2node dictionary
:param node2index: node2index dictionary
:return:type of list of tuple, ex.
[(node1, prob1),(node2, prob2),...]
"""
result = []
n = len(M)
v = np.zeros(n)
v[node2index[root]] = 1
while np.sum(abs(v - (alpha*np.matmul(M,v) + (1-alpha)*v))) > 0.0001:
v = alpha * np.matmul(M, v) + (1-alpha)*v
for ind, prob in enumerate(v):
result.append((index2node[ind], prob))
result = sorted(result, key=lambda x:x[1], reverse=True)[:num_candidates]
return result
def Generate_Transfer_Matrix(G):
"""generate transfer matrix given graph"""
index2node = dict()
node2index = dict()
for index,node in enumerate(G.keys()):
node2index[node] = index
index2node[index] = node
# num of nodes
n = len(node2index)
# generate Transfer probability matrix M, shape of (n,n)
M = np.zeros([n,n])
for node1 in G.keys():
for node2 in G[node1]:
# FIXME: some nodes not in the Graphs.keys, may incur some errors
try:
M[node2index[node2],node2index[node1]] = 1/len(G[node1])
except:
continue
return M, node2index, index2node
if __name__ == '__main__':
alpha = 0.85
root = 'A'
num_iter = 100
num_candidates = 10
G = {'A' : {'a' : 1, 'c' : 1},
'B' : {'a' : 1, 'b' : 1, 'c':1, 'd':1},
'C' : {'c' : 1, 'd' : 1},
'a' : {'A' : 1, 'B' : 1},
'b' : {'B' : 1},
'c' : {'A' : 1, 'B' : 1, 'C':1},
'd' : {'B' : 1, 'C' : 1}}
M, node2index, index2node = Generate_Transfer_Matrix(G)
# print transfer matrix
print(pd.DataFrame(M, index=G.keys(), columns=G.keys()))
result = PageRank(M, alpha, root)
# print results
print(result)
http://blog.csdn.net/gamer_gyt/article/details/47443877
https://baike.baidu.com/item/google%20pagerank/2465380?fr=aladdin&fromid=111004&fromtitle=pagerank
https://en.wikipedia.org/wiki/PageRank