zoukankan      html  css  js  c++  java
  • 谷歌PageRank算法

    1. 从Google网页排序到PageRank算法

    (1)谷歌网页怎么排序?

    • 先对搜索关键词进行分词,如“技术社区”分词为“技术”和“社区”;
    • 根据建立的倒排索引返回同时包含分词后结果的网页;
    • 将返回的网页相关性(类似上篇文章所讲的文本相似度)网页,相关性越高排名越靠前

    (2)怎么处理垃圾网页?
    那么问题来了,假如有某个垃圾网页中虽然也包含大量的查询词,但却并非满足用户需要的文档,因此,页面本身的重要性在网页排序中也起着很重要的作用。
    (3)如何度量网页本身的重要性?
    实际上互联网上的每一篇HTML文档除了包含文本、图片、视频等信息外,还包含了大量的链接关系,利用这些链接关系,能够发现某些重要的网页,其中网页是节点,网页间的链接关系是边。


    图片来自网络

    如上图,某网页1链向网页2,则可以认为网页1觉得网页2有链接价值,是比较重要的网页。某网页被指向的次数越多,则它的重要性越高;越是重要的网页,所链接的网页的重要性也越高。
    通过下图我们可以更形象地看出链向网页E的链接远远大于链向网页C的链接,但是网页C的重要性却大于网页E。这是因为网页C被网页B所链接,而网页B有很高的重要性。


    图片来自网络


    (4)PageRank核心思想
    PageRank对网页的排序可以独立于用户搜索进行。如果一个网页被很多其它网页所链接,说明它受到普遍的承认和信赖,那么它的排名就高。这就是 Page Rank 的核心思想。当然 Google 的 Page Rank 算法实际上要复杂得多。比如说,对来自不同网页的链接对待不同,本身网页排名高的链接更可靠,于是给这些链接予较大的权重。
    通俗理解,我们可以将互联网中的网页理解成我们现实中的每个人,人与人之间的联系就类似于网页与网页之间联系,一般人的社交影响力是跟其人脉的广度与人脉的质量有关,网页也同理,其重要性也跟网页的被链的数量与质量有关。
    具体参考:PageRank算法讲解PageRank算法--从原理到实现

    2 PageRank的python实现

    2.1 需求

    利用PageRank随机浏览模型求如下图个网页的PageRank值。


    网页关系

    即网页之间的关系如下表格:

    链接源ID链接目标 ID
    1 2,3,4,5, 7
    2 1
    3 1,2
    4 2,3,5
    5 1,3,4,6
    6 1,5
    7 5

    2.2 Python实现

     
    """
    Created on Sun Jan  8 23:41:29 2017
    
    @author: whenif
    """
    
    import numpy as np 
    import networkx as nx
    import matplotlib.pyplot as plt
    
    def getGm(A):
        '''
        功能:求状态转移概率矩阵Gm
        @A:网页链接图的邻接矩阵
        '''
        Gm = []   
        for i in range(len(A)):
            cnt = 0
            for j in range(len(A[i])):
             if A[i][j] != 0:
                 cnt += 1
            tran_prob = 1/cnt#转移概率
            Gm_tmp = []
            for j in range(len(A[i])):
             Gm_tmp.append(tran_prob*A[i][j])
            Gm.append(Gm_tmp)
        Gm = np.transpose(Gm) 
        return Gm
    
    def getBaseLev(N):
        '''
        功能:计算网页所获得的基本级别(1-P)*e/n 
        @N:网页总个数
        '''
        P = 0.85
        e = np.ones(N)
        R = [ [(1-P)*i*1/N] for i in e ]  
        return R
    
    
    def getPR(P,Gm,R,PR):
        '''
        功能:获取PR值
        @P:加权系数,通常取 0.85 左右,按照超链接进行浏览的概率
        @Gm:状态转移概率矩阵
        @R:网页所获得的基本级别
        @PR:每个网页节点的PageRank值
        '''
        #状态转移概率矩阵Gm与PR值相乘矩阵相乘
        Gm_PR = np.dot(Gm,PR) 
        #矩阵乘以常数P
        P_Gm_PR = P*Gm_PR
        #矩阵相加
        new_PR = P_Gm_PR+R #PR=P*Gm'PR+(1-d)*e/n PageRank算法的核心  
        return new_PR
    
    def res_vis(A,PR):
        '''
        将计算出来的值进行可视化展示
        @A:网页链接图的邻接矩阵
        @PR:每个网页节点最终的PageRank值
        '''
        #G=nx.Graph()构造的是无向图, G=nx.DiGraph()构造的是有向图
        #初始化有向图,节点数为7,edge(边)被创造的随机概率
        all_edges = []
        for i in range(7):
            for j in range(len(A)):
                if A[i][j]==1:
                    all_edges.append([i+1,j+1])         
        #(1)初始化有向图
        G = nx.DiGraph() 
        #(2)添加节点
        G.add_nodes_from(range(1,len(A)))
        #(3)添加有向边
        G.add_edges_from(all_edges)
        #(4)添加PR值
        pr = {}
        for i in range(len(PR)):
            pr[i+1] = PR[i][0]
        # (5)画图
        layout = nx.spring_layout(G)
        plt.figure(1)
        nx.draw(G, pos=layout, node_size=[x * 6000 for x in pr.values()],
                                      node_color='m',with_labels=True)
        plt.show() 
    
    def main():
        #初始化参数
        N = 7 #网页个数
        P = 0.85 #一个加权系数,通常取 0.85 左右,按照超链接进行浏览的概率
        #网页链接图的邻接矩阵,每一列表示一个网页的出度
        A =  np.array([[0,1,1,0,1,1,0],
                       [1,0,1,1,0,0,0],
                       [1,0,0,1,1,0,0],
                       [1,0,0,0,1,0,0],
                       [1,0,0,1,0,1,1],
                       [0,0,0,0,1,0,0],
                       [1,0,0,0,0,0,0]])
        A = np.transpose(A) #转置    
        #初始化PR值为0 
        new_PR = []  
        for i in range(N):  
            new_PR.append([0])       
        count = 0#迭代计数器
        while True:  
            PR = new_PR  
            R = getBaseLev(N)
            Gm = getGm(A)
            new_PR = getPR(P,Gm,R,PR)
            count = count +1
            print("第 %s 轮迭代" % count)
            print(str(round(new_PR[0][0],5)) 
                    +"	" + str(round(new_PR[1][0],5)) 
                    + "	" + str(round(new_PR[2][0],5)) 
                    + "	" + str(round(new_PR[3][0],5))
                    + "	" + str(round(new_PR[4][0],5))
                    + "	" + str(round(new_PR[5][0],5))
                    + "	" + str(round(new_PR[6][0],5)))
            #设置迭代条件
            if (    round(PR[0][0],5)==round(new_PR[0][0],5) 
                and round(PR[1][0],5)==round(new_PR[1][0],5) 
                and round(PR[2][0],5)==round(new_PR[2][0],5) 
                and round(PR[3][0],5)==round(new_PR[3][0],5)
                and round(PR[4][0],5)==round(new_PR[4][0],5)
                and round(PR[5][0],5)==round(new_PR[5][0],5)
                and round(PR[6][0],5)==round(new_PR[6][0],5)):   
                break
        print("-------------------")
        print("PageRank值已计算完成")
        res_vis(A,new_PR)
    
    if __name__ == '__main__':  
        main()
    

    2.3 结果与分析

    (1)迭代结果

     
    第 1 轮迭代
    0.02143 0.02143 0.02143 0.02143 0.02143 0.02143 0.02143
    第 2 轮迭代
    0.06241 0.04025 0.0357  0.02963 0.05846 0.02598 0.02507
    ......
    第 57 轮迭代
    0.28026 0.15875 0.13887 0.10821 0.18418 0.06057 0.06907
    第 58 轮迭代
    0.28026 0.15875 0.13887 0.10821 0.18418 0.06057 0.06907
    -------------------
    PageRank值已计算完成
    

      

    (2)可视化结果


    网页关系可视化结果


    其中圆圈编号表示网页ID,圆圈大小表示PR值大小,连线表示网页之间的关系,有带黑色箭头表示出度方向。
    (3)结果汇总

    名次PageRank值网页ID发出链接ID被链接ID
    1 0.28026 1 2,3,4,5,7 2,3,5,6
    2 0.18418 5 1,3,4,6 1,4,6,7
    3 0.15875 2 1 1,3,4
    4 0.13887 3 1,2 1,4,5
    5 0.10821 4 2,3,5 1,5
    6 0.06907 7 5 1
    7 0.06057 6 1,5 5

    (4)结果分析

    • 被链接个数越多其PageRank值越大,当被链接个数相同则发出链接个数越多其PageRank值越大;
    • ID=1的页面的PageRank值是0.28026,占据全体接近三分之一,成为了第1位。从可视化图与结果汇总表格可以看出,因为ID=1页面是链出链接和链入链接最多的页面,也可以理解它是最受欢迎的页面。
      同时需要注意的是在PageRank值排在第3位的ID=2页面,被3个链接所链接,而只有面向ID=1页面发出一个链接,因此(面向ID=1页面的)链接就得到ID=2的所有的PageRank值。

    附另一个简单的PageRank程序:

    from numpy import *  
      
    a = 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 = zeros((a.shape),dtype = float)  
        for i in range(a.shape[0]):  
            for j in range(a.shape[1]):  
                c[i][j] = a[i][j] / (a[:, j].sum())  #完成初始化分配  
        return c  
      
    def pageRank(p,m,v):  #计算pageRank值
        #判断pr矩阵是否收敛,(v == p*dot(m,v) + (1-p)*v).all()判断前后的pr矩阵是否相等,若相等则停止循环  
        while((v == p*dot(m,v) + (1-p)*v).all()==False):  
            v = p*dot(m,v) + (1-p)*v  
        return v  
      
    if __name__=="__main__":  
        M = graphMove(a)
        pr = array([float(1)/M.shape[0] for _ in range(M.shape[0])]) #pr值的初始化  
        p = 0.8           #引入浏览当前网页的概率为p,假设p=0.8  
        print pageRank(p,M,pr)  # 计算pr值
    

      

    3 应用场景

    在数据分析我们经常需要从用户的角度思考问题,如用户购买路径,用户之所以没产生购买,那么到底是在哪个环节出现了问题?基于用户还有许许多多的分析问题,如流失用户分析、流失用户预警、用户信用度分析等。
    从基于用户的分析我们可以延伸到用户与信息、用户与商品、用户与用户之间的分析,当然这三点对号入座的便分别是BAT的基因所在,其中人与人之间的分析即是社交关系分析,这也是PageRank适合的领域之一。在不同行业的应用场景不用,如以下应用场景:

    • 微信、微博等应用的社交网络分析,可以实现基于用户的相似度的内容推荐、可以挖掘用户的价值、用户的社交影响力等;电商如京东等可利用用户关系,在一定程度上协助风险控制(抓刷单等)。
    • 在电信行业中利用交往圈数据可以得到用户的社交影响力,从而在一定程度上可以协助垃圾短信等的治理;
    • 文献重要性研究(引用与被引用)
    • ......

    后记

    数据分析与挖掘很多都是从人出发,逐渐延伸到人与人,甚至是人、人与人在时间与空间上的表现,其中人与人之间的关系可以说是很重要的一环,所以个人觉得PageRank还是有挺大的应用性,在工作中也是深有体会。当然文中只是举了简单的例子并实现,代码可优化的地方应该不少,望各路小伙伴一起交流一起进步。



    作者:whenif
    链接:http://www.jianshu.com/p/5657910d7df6
  • 相关阅读:
    css控制textarea固定大小不可拖动
    js绑定回车事件
    这一周的收获与总结_BP
    20140824
    【转】Hadooop学习笔记
    【转】CUDA优化小记录
    【转】CUDA程序优化要点
    cublas 矩阵相乘API详解
    CUDA 矩阵相乘完整代码
    CUDA 矩阵相乘
  • 原文地址:https://www.cnblogs.com/shixiangwan/p/7593923.html
Copyright © 2011-2022 走看看