ageRank和TextRank
PageRank
PageRank原理
pangRank是用于对网页进行排名的算法。通俗的讲就是对每个网页进行打分,根据得分高低进行排序。怎么打分?
打分思路如下:
1.假如有个网页C
2.当连接(其他网页可以跳转到C)到C的网页越多(A和B的数量越多),C的比重(pagerank值)应该越高。
3.当链接到C的网页的本身比重越高时(A和B本身体的分数越高),C的比重应该越高。
PageRank论文:
《The PageRank Citation Ranking: Bringing Order to the Web》
具体实现:
假设互联网是一个有向图,ABC三个节点代表网页,每条边代表转移比重。
每个网页都会以等概率跳转到它链接到的网页,跳转是随机的,这就形成了一个随机游走模型,即一阶马尔可夫链 。初始化时每个节点的权重都是1,随着不断的跳转,不断的迭代。这个马尔科夫链会逐渐的形成一种平稳分布。
权重(PageRank值)的计算公示如下:
公式来源于何晗:自然语言处理入门, S ( v i ) S(v_i) S(vi)是某个节点的权重,初始都是1,d是介于(0,1)之间的常熟因子,模拟用户通过点击链接跳转到这个页面的概览,1-d就是用户通过输入网址到这个页面的概览。 I n ( v i ) In(v_i) In(vi)表示能链接到 V i V_i Vi的节点的集合, O u t ( V j ) Out(V_j) Out(Vj)表示从 V j V_j Vj出发的链接的集合。所以从 V − j V-j V−j发出的链接越多,每个链接的权重就越小。以figure2为例,权重为9的节点,总过发出了3条链接,则每条链接的权重为9/3=3。
PageRank程序设计
以figure3为例,假设有ABC三个节点,初始时刻三个节点的权重都是1,
设计程序计算ABC最终的权重:
#coding=utf8
class Node():
#初始化一个节点
def __init__(self, value=1, childrens=set(), name=''):
'''初始时刻所有节点的权重都是1'''
self.value = value
self.childrens = childrens
self.name = name
def __repr__(self):
return self.name
class PageRank():
#初始化有向图
def __init__(self, allNode=[]):
self.allNode = allNode
#一次迭代计算(也可以改写成一遍计算一遍迭代的方式,如下)
def cal(self, d):
values = []
for i in self.allNode:
values.append((1-d) + d*(sum([j.value/len(j.childrens) if i in j.childrens else 0 for j in self.allNode])))
for i,j in zip(self.allNode,values):
i.value = j
#def cal(self, d):
#for i in self.allNode:
#i.value = (1-d) + d*(sum([j.value/len(j.childrens) if i in j.childrens else 0 for j in self.allNode]))
def computer(self, Num, threshold):
'''Num是迭代次数,threshold是阈值当总体权重变化量小于这个值时停止迭代'''
#生成需要打印的东西
text1 = '{0:<15}'
text2 = '{0:<15}'
for indx,Node in enumerate(self.allNode):
text1 += '{{{}:<15}}'.format(indx+1)
text2 += '{{{}:<15.8f}}'.format(indx+1)
print(text1.format('iteration',*['PR({0})'.format(i) for i in self.allNode]))
#开始迭代
count = 0
while count<=Num:
print(text2.format(count,*[i.value for i in self.allNode]))
values = [i.value for i in self.allNode]
self.cal(0.5)
new_values = [i.value for i in self.allNode]
count += 1
if sum([abs(i-j) for i, j in zip(values, new_values)])<=threshold:
break
if __name__ == '__main__':
A = Node(value=1,name='A')
B = Node(value=1,name='B')
C = Node(value=1,name='C')
A.childrens = {B,C}
B.childrens = {C}
C.childrens = {A}
pagerank = PageRank(allNode=[A,B,C])
pagerank.computer(100,0.00000001)
最终计算结果:
PageRank的向量表示
上述迭代过程可用矩阵相乘的形式表示,初始状态向量为: R 0 = [ 1.0 , 1.0 , 1.0 ] T R_0 = [1.0,1.0,1.0]^T R0=[1.0,1.0,1.0]T ,
转移矩阵(有的称呼为概览转移矩阵、状态转移矩阵)为: M = [ [ 0 , 0 , 1 ] , [ 0.5 , 0 , 0 ] , [ 0.5 , 1 , 0 ] ] M=[[0, 0, 1],[0.5, 0, 0],[0.5, 1, 0]] M=[[0,0,1],[0.5,0,0],[0.5,1,0]]
则一次迭代的结果为:
R 1 = ( 1 − d ) ⋅ ( e e t n ⋅ R 0 ) + d ⋅ M ⋅ R 0 R_1 = (1-d)·(\frac{ee^t}{n}·R_0) + d·M·R_0 R1=(1−d)⋅(neet⋅R0)+d⋅M⋅R0 ,其中e为单位列向量,eeT为n*n的1矩阵。n为节点个数,在此为3 。
则 R 1 = 0.5 ∗ [ 1 , 1 , 1 ] + 0.5 ∗ [ 1 , 0.5 , 1.5 ] = [ 1 , 0.75 , 1.25 ] R_1 = 0.5*[1,1,1] + 0.5*[1,0.5,1.5] = [1,0.75,1.25] R1=0.5∗[1,1,1]+0.5∗[1,0.5,1.5]=[1,0.75,1.25]
以此类推:
转移矩阵M如下:
pagerank程序设计-矩阵
import numpy as np
class Node():
#初始化一个节点
def __init__(self, value=1, childrens=set(), name=''):
'''初始时刻所有节点的权重都是1'''
self.value = value
self.childrens = childrens
self.name = name
def __repr__(self):
return self.name
class PageRank():
#初始化有向图
def __init__(self, allNode=[]):
self.allNode = allNode
self.state = np.array([i.value for i in self.allNode])
self.Matric()
#生成转移矩阵
def Matric(self):
values = []
for i in self.allNode:
values.append([j.value/len(j.childrens) if i in j.childrens else 0 for j in self.allNode])
self.metric = np.array(values)
#一次迭代计算
def cal(self, d):
self.state = (1-d)/len(self.allNode)*np.ones([len(self.allNode),len(self.allNode)])@self.state + d*self.metric@self.state
for i,j in zip(self.allNode,list(self.state)):
i.value = j
def computer(self, Num, threshold):
'''Num是迭代次数,threshold是阈值当总体权重变化量小于这个值时停止迭代'''
#生成需要打印的东西
text1 = '{0:<15}'
text2 = '{0:<15}'
for indx,Node in enumerate(self.allNode):
text1 += '{{{}:<15}}'.format(indx+1)
text2 += '{{{}:<15.8f}}'.format(indx+1)
print(text1.format('iteration',*['PR({0})'.format(i) for i in self.allNode]))
#开始迭代
count = 0
while count<=Num:
print(text2.format(count,*[i.value for i in self.allNode]))
values = [i.value for i in self.allNode]
self.cal(0.5)
new_values = [i.value for i in self.allNode]
count += 1
if sum([abs(i-j) for i, j in zip(values, new_values)])<=threshold:
break
if __name__ == '__main__':
A = Node(value=1,name='A')
B = Node(value=1,name='B')
C = Node(value=1,name='C')
A.childrens = {B,C}
B.childrens = {C}
C.childrens = {A}
pagerank = PageRank(allNode=[A,B,C])
pagerank.computer(100,0.00001)
计算结果:
TextRank
TextRank从google的网页排序算法脱胎而来,是一种基于图结构的应用于文本处理排序的无监督模型,可以应用在关键词和关键句的抽取。
TextRank关键词提取
将单词视为节点,每个单词的外联来自,身前身后固定大小的窗口内的所有单词。如下图所示:
图片来源:何晗:自然语言处理入门