PageRank算法与python实现

概述

PageRank的Page可是认为是网页,表示网页排名,也可以认为是Larry Page(google 产品经理),因为他是这个算法的发明者之一,还是google CEO。PageRank算法计算每一个网页的PageRank值,然后根据这个值的大小对网页的重要性进行排序。

算法思想

  • 如果一个网页被很多其他网页链接到的话说明这个网页比较重要,也就是PageRank值会相对较高
  • 如果一个PageRank值很高的网页链接到一个其他的网页,那么被链接到的网页的PageRank值会相应地因此而提高
  • 模拟一个悠闲的上网者,上网者首先随机选择一个网页打开,然后在这个网页上呆了几分钟后,跳转到该网页所指向的链接,这样无所事事、漫无目的地在网页上跳来跳去,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 的nwei维向量 V0 V 0 ,可以通过如下方式进行迭代

V1=MV0=01/31/31/31/2001/2100001/21/201/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=MVi1 V i = M V i − 1
不断的迭代计算,直到 |Vi+1Vi|<ϵ | V i + 1 − V i | < ϵ Vi V i 不再变化为止。最终会收敛到一个恒定值,得到各个网页访问的概率
上述上网者的行为是一个马尔科夫过程的实例,要满足收敛性,需要具备一个条件:图是强连通的,即从任意网页可以到达其他任意网页

常见问题

  • 终止点问题:互联网上的网页不满足强连通的特性,因为有一些网页不指向任何网页,如果按照上面的计算,上网者到达这样的网页后便走投无路、四顾茫然,导致前面累计得到的转移概率被清零,这样下去,最终的得到的概率分布向量所有元素几乎都为0
  • 陷阱问题:另外一个问题就是陷阱问题,即有些网页不存在指向其他网页的链接,但存在指向自己的链接

Pagerank模型的完善

假定上网者在每一步,都可能不想看当前网页了,而是在地址栏输入另外一个地址,而地址栏跳转到各个网页的概率是 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.8501/31/31/31/2001/2100001/21/201/41/41/41/4+0.151/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+1Vi|<ϵ | 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)

reference

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

PageRank是一种用于网页排名的算法,由Google创始人拉里·佩奇(Larry Page)和谢尔盖·布林(Sergey Brin)在1998年发明,它基于链接分析的思想,通过计算网页之间的“重要性”得分,从而确定其在搜索引擎结果中的位置。 在Python实现PageRank算法,你可以使用网络流库如`networkx`和`scipy.sparse`。以下是一个简单的步骤概述: 1. **安装必要的库**: ```bash pip install networkx scipy ``` 2. **创建图(Graph)**: 使用`networkx`中的`DiGraph`或`MultiDiGraph`来表示网页及其间的链接。 ```python import networkx as nx # 创建一个空有向图 G = nx.DiGraph() ``` 3. **添加节点和边**: 将网页作为节点,边表示从源到目标的链接。 ```python # 添加节点和边的字典或列表形式 nodes = ['A', 'B', 'C', ...] edges = [('A', 'B'), ('B', 'C'), ('B', 'D'), ...] G.add_nodes_from(nodes) G.add_edges_from(edges) ``` 4. **初始化PageRank矩阵**: 网页总数为n,初始的PageRank通常是所有节点的均值,除以n。 ```python n = len(G.nodes) initial_PR = [1 / n] * n PR_matrix = nx.to_numpy_array(G) + nx.laplacian_matrix(G).todense() ``` 5. **迭代更新PageRank**: 这通常涉及到迭代地应用转移矩阵(PR_matrix),直到收敛。 ```python def iteration(PR, convergence_threshold): new_PR = PR @ PR_matrix delta = sum(abs(new_PR - PR)) if delta < convergence_threshold: return new_PR else: PR = new_PR # 调整阈值并继续迭代,例如减半 convergence_threshold /= 2 return iteration(PR, convergence_threshold) final_PR = iteration(initial_PR, 0.0001) ``` 6. **显示结果**: 打印每个节点的PageRank分数。 ```python for node, rank in zip(G.nodes, final_PR): print(f"Node {node}: Rank {rank}") ```
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值