networkx 有向图强连通_机器学习手记[8]--Python Networkx库中PageRank算法实现源码分析...

机器学习手记[8]--Python Networkx库中PageRank算法实现源码分析

网上对 Page 算法讲解的很多,实现代码也很多很杂, 所以为了找到一个更高质量的 PageRank 算法的实现,

我阅读了 Python Networkx 库上自带的 pagerank 方法的源码。部分多余内容我删除了,有兴趣可以直接下这个库查看源码

源码的地址在 http://networkx.github.io/download.html

具体的 pagerank 代码我已经上传到网盘在 http://pan.baidu.com/s/1ntOafH3

PageRank 算法最主要的地方在于对两个问题的解决,一个是 dangling nodes,一个是 spider trap

前者是说,没有引用其他网页的链接,用图角度的理解就是出度为 0。

后者是说,进入到一个网页或者几个网页,这个单个网页,或者几个网页之间相互引用,这样资源进去后就一直在里面转,出不来了,造成 rank sink 问题。

对于 dangling nodes,我们可以计算他们的 PR 贡献值, 然后均分给所有节点

对于 spider trap,需要用心灵漂移的方式去解决。

Networkx 库里面,主要有三种计算 PageRank 的方法(PS 为什么是三种,我直观觉得是因为这是三个人写的,因为连某些效果完全相同的初始化语句,三个写的都不一样)

1 pagerank 函数

以图结构为基础

通过迭代收敛方法计算 PR 值 (PageRank 值)

2 pagerank_numpy 函数

将图转换为 numpy 邻接矩阵,

通过 google_matrix 和 numpy 矩阵计算

通过计算最大特征值对应的主特征向量,即为所求 PR 值

3 pagerank_scipy 函数

将图转换为 sparse 稀疏矩阵

通过迭代收敛方法计算 PR 值

"""PageRank analysis of graph structure. """#BSD license.#NetworkX: http: //networkx.lanl.gov/

importnetworkxasnx@not_implemented_for('multigraph')defpagerank(G,alpha=0.85,personalization=None,max_iter=100,tol=1.0e-6,nstart=None,weight='weight',dangling=None):"""Return the PageRank of the nodes in the graph.

Parameters

-----------

G : graph

A NetworkX graph. 在PageRank算法里面是有向图

alpha : float, optional

稳定系数, 默认0.85, 心灵漂移teleporting系数,用于解决spider trap问题

personalization: dict, optional

个性化向量,确定在分配中各个节点的权重

格式举例,比如四个点的情况: {1:0.25,2:0.25,3:0.25,4:0.25}

默认个点权重相等,也可以给某个节点多分配些权重,需保证权重和为1.

max_iter : integer, optional

最大迭代次数

tol : float, optional

迭代阈值

nstart : dictionary, optional

整个网络各节点PageRank初始值

weight : key, optional

各边权重

dangling: dict, optional

字典存储的是dangling边的信息

key --dangling边的尾节点,也就是dangling node节点

value --dangling边的权重

PR值按多大程度将资源分配给dangling node是根据personalization向量分配的

This must be selected to result in an irreducible transition

matrix (see notes under google_matrix). It may be common to have the

dangling dict to be the same as the personalization dict.

Notes

-----

特征值计算是通过迭代方法进行的,不能保证收敛,当超过最大迭代次数时,还不能减小到阈值内,就会报错

"""#步骤一:图结构的准备--------------------------------------------------------------------------------

iflen(G)==0:return{}

ifnotG.is_directed():D=G.to_directed()

else:D=G#Create a copy in (right) stochastic form W = nx.stochastic_graph(D, weight = weight) N = W.number_of_nodes()#确定PR向量的初值

ifnstartisNone:x=dict.fromkeys(W,1.0/N)#和为1

else:#Normalized nstart vector s = float(sum(nstart.values())) x = dict((k, v / s) for k, v in nstart.items()) if personalization is None: #Assign uniform personalization vector

ifnotgiven p=dict.fromkeys(W,1.0/N)

else:missing=set(G)-set(personalization)ifmissing:raiseNetworkXError('Personalization dictionary ''must have a value for every node. ''Missing nodes %s'%missing)s=float(sum(personalization.values()))p=dict((k,v/s)fork,vinpersonalization.items())#归一化处理

ifdanglingisNone:#Use personalization vector

ifdangling vectornotspecified dangling_weights=p

else:missing=set(G)-set(dangling)ifmissing:raiseNetworkXError('Dangling node dictionary ''must have a value for every node. ''Missing nodes %s'%missing)s=float(sum(dangling.values()))dangling_weights=dict((k,v/s)fork,vindangling.items())dangling_nodes=[n

forninW

ifW.out_degree(n,weight=weight)==0.0]#dangling_nodes dangling节点#danglesum dangling节点PR总值

#dangling初始化默认为personalization#dangling_weights根据dangling而生成,决定dangling node资源如何分配给全局的矩阵#迭代计算--------------------------------------------------------------------

#PR = alpha * (A * PR + dangling分配) + (1 - alpha) * 平均分配#也就是三部分,A * PR其实是我们用图矩阵分配的,dangling分配则是对dangling node的PR值进行分配, (1 - alpha)分配则是天下为公大家一人一份分配的#其实通俗的来说,我们可以将PageRank看成抢夺大赛,有三种抢夺机制。#1,A * PR这种是自由分配,大家都愿意参与竞争交流的分配#2,dangling是强制分配,有点类似打倒土豪分田地的感觉,你不参与自由市场,那好,我们就特地帮你强制分。#3,平均分配,其实就是有个机会大家实现共产主义了,不让spider trap这种产生rank sink的节点捞太多油水,其实客观上也是在帮dangling分配。#从图和矩阵的角度来说,可以这样理解,我们这个矩阵可以看出是个有向图#矩阵要收敛-->矩阵有唯一解-->n阶方阵对应有向图是强连通的-->两个节点相互可达,1能到2,

2能到1#如果是个强连通图,就是我们上面说的第1种情况,自由竞争,那么我们可以确定是收敛的#不然就会有spider trap造成rank sink问题

for_inrange(max_iter):xlast=x x=dict.fromkeys(xlast.keys(),0)#x初值danglesum=alpha*sum(xlast[n]

fornindangling_nodes)#第2部分:计算dangling_nodes的PR总值

forninx:fornbrinW[n]:x[nbr]+=alpha*xlast[n]*W[n][nbr][weight]#第1部分:将节点n的PR资源分配给各个节点,循环之

forninx:x[n]+=danglesum*dangling_weights[n]+(1.0-alpha)*p[n]#第3部分:节点n加上dangling nodes和均分的值#迭代检查err=sum([abs(x[n]-xlast[n])forninx])iferr

Parameters

-----------

和PageRank参数表相似

Returns

-------

A : NumPy matrix

Google matrix of the graph

Notes

-----

这个方法返回的"谷歌矩阵" 描述了PageRank用到的马尔科夫链。

PageRank需要收敛的话,就需要方程有唯一解,这样过度矩阵必须是不可約的。

用图的角度讲,就是说两个点之间必须相互可达,节点1能到节点2,节点2也有路径到1。

不然的话,会出现spider trap,导致rank sink问题出现,造成矩阵无法收敛,集中到sink节点了。

The matrix returned represents the transition matrix that describes the

Markov chain used in PageRank. For PageRank to converge to a unique

solution (i.e., a unique stationary distribution in a Markov chain), the

transition matrix must be irreducible. In other words, it must be that

there exists a path between every pair of nodes in the graph, or else there

is the potential of "rank sinks."

"""importnumpyasnp

ifnodelistisNone:nodelist=G.nodes()M=nx.to_numpy_matrix(G,nodelist=nodelist,weight=weight)N=len(G)ifN==0:returnM#Personalization vector

ifpersonalizationisNone:p=np.repeat(1.0/N,N)

else:missing=set(nodelist)-set(personalization)ifmissing:raiseNetworkXError('Personalization vector dictionary ''must have a value for every node. ''Missing nodes %s'%missing)p=np.array([personalization[n]

forninnodelist],dtype=float)p/=p.sum()#Danglingnodes

ifdanglingisNone:dangling_weights=p

else:missing=set(nodelist)-set(dangling)ifmissing:raiseNetworkXError('Dangling node dictionary ''must have a value for every node. ''Missing nodes %s'%missing)#确定dangling node的PR资源的分配矩阵dangling_weights=np.array([dangling[n]

forninnodelist],dtype=float)dangling_weights/=dangling_weights.sum()dangling_nodes=np.where(M.sum(axis=1)==0)[0]#计算行和为0,也就是计算出度为0的节点,就是dangling nodes#Assign dangling_weights to any dangling nodes(nodes with no out links) for node in dangling_nodes: M[node] = dangling_weights#将这个的出度直接设成平均分配M /= M.sum(axis = 1)#归一化#这个时候M矩阵已经解决了dangling node的问题,再通过1 - alpha解决

returnalpha*M+(1-alpha)*np.outer(np.ones(N),p)defpagerank_numpy(G,alpha=0.85,personalization=None,weight='weight',dangling=None):"""

备注

特征向量计算,是利用了Numpy在LAPACK库的方法进行的,对小型图的计算非常快速精确

"""importnumpyasnp

iflen(G)==0:return{}

M=google_matrix(G,alpha,personalization=personalization,weight=weight,dangling=dangling)#usenumpy LAPACK solver eigenvalues,

eigenvectors=np.linalg.eig(M.T)ind=eigenvalues.argsort()#eigenvector of largest eigenvalue at ind[-1],

normalized largest=np.array(eigenvectors[:,ind[-1]]).flatten().real norm=float(largest.sum())returndict(zip(G,map(float,largest/norm)))defpagerank_scipy(G,alpha=0.85,personalization=None,max_iter=100,tol=1.0e-6,weight='weight',dangling=None):"""

-----

该方法应用的是SciPy库,实现方法和第一个:pagerank函数是基本一致的

-----

备注

特征向量计算,是利用了SciPy库稀疏矩阵计算

"""importscipy.sparse N=len(G)ifN==0:return{}

nodelist=G.nodes()M=nx.to_scipy_sparse_matrix(G,nodelist=nodelist,weight=weight,dtype=float)S=scipy.array(M.sum(axis=1)).flatten()S[S!=0]=1.0/S[S!=0]Q=scipy.sparse.spdiags(S.T,0,*M.shape,format='csr')M=Q*M#初始化PageRank值x = scipy.repeat(1.0 / N, N)#确定personalization字典,各节点分配权重,默认权重相同

ifpersonalizationisNone:p=scipy.repeat(1.0/N,N)

else:missing=set(nodelist)-set(personalization)ifmissing:raiseNetworkXError('Personalization vector dictionary ''must have a value for every node. ''Missing nodes %s'%missing)p=scipy.array([personalization[n]

forninnodelist],dtype=float)p=p/p.sum()#Danglingnodes的确定和资源配置

ifdanglingisNone:dangling_weights=p

else:missing=set(nodelist)-set(dangling)ifmissing:raiseNetworkXError('Dangling node dictionary ''must have a value for every node. ''Missing nodes %s'%missing)#Convertthe dangling dictionaryintoan arrayinnodelist order dangling_weights=scipy.array([dangling[n]

forninnodelist],dtype=float)dangling_weights/=dangling_weights.sum()is_dangling=scipy.where(S==0)[0]#迭代#第1部分:x*M,

第2部分dangling node分配,

第3部分rank sink解决

for_inrange(max_iter):xlast=x x=alpha*(x*M+sum(x[is_dangling])*dangling_weights)+(1-alpha)*p#check convergence,

l1 norm err=scipy.absolute(x-xlast).sum()iferr

来源: http://lib.csdn.net/article/python/43404

你可能感兴趣的:(networkx,有向图强连通)