Source code for networkx.algorithms.link_analysis.pagerank_alg

"""图结构的PageRank分析。"""

from warnings import warn

import networkx as nx

__all__ = ["pagerank", "google_matrix"]


[docs] @nx._dispatchable(edge_attrs="weight") def pagerank( G, alpha=0.85, personalization=None, max_iter=100, tol=1.0e-6, nstart=None, weight="weight", dangling=None, ): """返回图中节点的PageRank值。 PageRank根据图中入链的结构计算节点的排名。它最初设计为一种网页排名算法。 Parameters ---------- G : 图 一个NetworkX图。无向图将被转换为一个有向图,每条无向边对应两条有向边。 alpha : 浮点数, 可选 PageRank的阻尼参数,默认为0.85。 personalization: 字典, 可选 由包含图节点子集及其个性化值的字典组成的“个性化向量”。至少一个个性化值必须非零。如果未指定,节点的个性化值将为零。默认使用均匀分布。 max_iter : 整数, 可选 幂方法特征值求解器中的最大迭代次数。 tol : 浮点数, 可选 用于检查幂方法求解器中收敛性的误差容限。迭代将在达到 ``len(G) * tol`` 的容限后停止。 nstart : 字典, 可选 每个节点的PageRank迭代初始值。 weight : 键, 可选 用作权重的边数据键。如果为None,权重设置为1。 dangling: 字典, 可选 分配给任何“悬挂”节点的出边,即没有出边的节点。字典键是出边指向的节点,字典值是该出边的权重。默认情况下,悬挂节点根据个性化向量(如果未指定则为均匀分布)分配出边。这必须选择以产生不可约的转移矩阵(参见google_matrix下的注释)。通常,悬挂字典与个性化字典相同。 Returns ------- pagerank : 字典 包含节点及其PageRank值的字典 Examples -------- >>> G = nx.DiGraph(nx.path_graph(4)) >>> pr = nx.pagerank(G, alpha=0.9) Notes ----- 特征向量的计算通过幂迭代方法进行,没有收敛保证。迭代将在达到 ``len(G) * tol`` 的误差容限后停止。如果迭代次数超过 `max_iter` ,将引发:exc:`networkx.exception.PowerIterationFailedConvergence` 异常。 PageRank算法是为有向图设计的,但此算法不检查输入图是否为有向图,并在无向图上执行时将每条边转换为两条有向边。 See Also -------- google_matrix Raises ------ PowerIterationFailedConvergence 如果算法在指定的幂迭代方法迭代次数内未收敛到指定的容限。 References ---------- .. [1] A. Langville and C. Meyer, "A survey of eigenvector methods of web information retrieval." http://citeseer.ist.psu.edu/713792.html .. [2] Page, Lawrence; Brin, Sergey; Motwani, Rajeev and Winograd, Terry, The PageRank citation ranking: Bringing order to the Web. 1999 http://dbpubs.stanford.edu:8090/pub/showDoc.Fulltext?lang=en&doc=1999-66&format=pdf """ return _pagerank_scipy( G, alpha, personalization, max_iter, tol, nstart, weight, dangling )
def _pagerank_python( G, alpha=0.85, personalization=None, max_iter=100, tol=1.0e-6, nstart=None, weight="weight", dangling=None, ): if len(G) == 0: return {} D = G.to_directed() # Create a copy in (right) stochastic form W = nx.stochastic_graph(D, weight=weight) N = W.number_of_nodes() # Choose fixed starting vector if not given if nstart is None: x = dict.fromkeys(W, 1.0 / N) else: # Normalized nstart vector s = sum(nstart.values()) x = {k: v / s for k, v in nstart.items()} if personalization is None: # Assign uniform personalization vector if not given p = dict.fromkeys(W, 1.0 / N) else: s = sum(personalization.values()) p = {k: v / s for k, v in personalization.items()} if dangling is None: # Use personalization vector if dangling vector not specified dangling_weights = p else: s = sum(dangling.values()) dangling_weights = {k: v / s for k, v in dangling.items()} dangling_nodes = [n for n in W if W.out_degree(n, weight=weight) == 0.0] # power iteration: make up to max_iter iterations for _ in range(max_iter): xlast = x x = dict.fromkeys(xlast.keys(), 0) danglesum = alpha * sum(xlast[n] for n in dangling_nodes) for n in x: # this matrix multiply looks odd because it is # doing a left multiply x^T=xlast^T*W for _, nbr, wt in W.edges(n, data=weight): x[nbr] += alpha * xlast[n] * wt x[n] += danglesum * dangling_weights.get(n, 0) + (1.0 - alpha) * p.get(n, 0) # check convergence, l1 norm err = sum(abs(x[n] - xlast[n]) for n in x) if err < N * tol: return x raise nx.PowerIterationFailedConvergence(max_iter)
[docs] @nx._dispatchable(edge_attrs="weight") def google_matrix( G, alpha=0.85, personalization=None, nodelist=None, weight="weight", dangling=None ): """返回图的Google矩阵。 Parameters ---------- G : 图 一个NetworkX图。无向图将被转换为一个有向图,每条无向边对应两条有向边。 alpha : 浮点数 阻尼因子。 personalization: 字典, 可选 由包含图节点子集及其个性化值的字典组成的“个性化向量”。至少一个个性化值必须非零。如果未指定,节点的个性化值将为零。默认情况下,使用均匀分布。 nodelist : 列表, 可选 行和列根据nodelist中的节点排序。如果nodelist为None,则排序由G.nodes()生成。 weight : 键, 可选 用作权重的边数据键。如果为None,权重设置为1。 dangling: 字典, 可选 分配给任何“悬空”节点的出边,即没有出边的节点。字典键是出边指向的节点,字典值是该出边的权重。默认情况下,悬空节点根据个性化向量(如果未指定则为均匀分布)分配出边。这必须选择以产生不可约的转移矩阵(见下面的注释)。通常,悬空字典与个性化字典相同。 Returns ------- A : 2D NumPy ndarray 图的Google矩阵 Notes ----- 返回的数组表示描述PageRank中使用的马尔可夫链的转移矩阵。为了使PageRank收敛到唯一解(即马尔可夫链中的唯一平稳分布),转移矩阵必须是不可约的。换句话说,图中每对节点之间必须存在路径,否则可能存在“排名下沉”。 此实现适用于多(有向)图。对于多图,两个节点之间的权重设置为这两个节点之间所有边权重的总和。 See Also -------- pagerank """ import numpy as np if nodelist is None: nodelist = list(G) A = nx.to_numpy_array(G, nodelist=nodelist, weight=weight) N = len(G) if N == 0: return A # Personalization vector if personalization is None: p = np.repeat(1.0 / N, N) else: p = np.array([personalization.get(n, 0) for n in nodelist], dtype=float) if p.sum() == 0: raise ZeroDivisionError p /= p.sum() # Dangling nodes if dangling is None: dangling_weights = p else: # Convert the dangling dictionary into an array in nodelist order dangling_weights = np.array([dangling.get(n, 0) for n in nodelist], dtype=float) dangling_weights /= dangling_weights.sum() dangling_nodes = np.where(A.sum(axis=1) == 0)[0] # Assign dangling_weights to any dangling nodes (nodes with no out links) A[dangling_nodes] = dangling_weights A /= A.sum(axis=1)[:, np.newaxis] # Normalize rows to sum to 1 return alpha * A + (1 - alpha) * p
def _pagerank_numpy( G, alpha=0.85, personalization=None, weight="weight", dangling=None ): """返回图中节点的PageRank值。 PageRank根据图G中入链的结构计算节点排名。它最初被设计为一种网页排名算法。 Parameters ---------- G : 图 一个NetworkX图。无向图将被转换为一个有向图,每条无向边对应两条有向边。 alpha : 浮点数, 可选 PageRank的阻尼参数,默认为0.85。 personalization: 字典, 可选 由包含图节点子集及其个性化值的字典组成的“个性化向量”。至少一个个性化值必须非零。如果未指定,节点的个性化值将为零。默认使用均匀分布。 weight : 键, 可选 用作权重的边数据键。如果为None,权重设为1。 dangling: 字典, 可选 分配给任何“悬挂”节点的出边,即没有出边的节点。字典键是出边指向的节点,字典值是该出边的权重。默认情况下,悬挂节点根据个性化向量(如果未指定则为均匀分布)分配出边。这必须选择以产生不可约的转移矩阵(参见google_matrix下的注释)。通常,悬挂字典与个性化字典相同。 Returns ------- pagerank : 字典 包含节点及其PageRank值的字典。 Examples -------- >>> from networkx.algorithms.link_analysis.pagerank_alg import _pagerank_numpy >>> G = nx.DiGraph(nx.path_graph(4)) >>> pr = _pagerank_numpy(G, alpha=0.9) Notes ----- 特征向量计算使用NumPy与LAPACK特征值求解器的接口。这对于小图来说是最快且最准确的。 此实现适用于多(有向)图。对于多图,两个节点之间的权重设置为这两个节点之间所有边权重的总和。 See Also -------- pagerank, google_matrix References ---------- .. [1] A. Langville and C. Meyer, "A survey of eigenvector methods of web information retrieval." http://citeseer.ist.psu.edu/713792.html .. [2] Page, Lawrence; Brin, Sergey; Motwani, Rajeev and Winograd, Terry, The PageRank citation ranking: Bringing order to the Web. 1999 http://dbpubs.stanford.edu:8090/pub/showDoc.Fulltext?lang=en&doc=1999-66&format=pdf """ import numpy as np if len(G) == 0: return {} M = google_matrix( G, alpha, personalization=personalization, weight=weight, dangling=dangling ) # use numpy LAPACK solver eigenvalues, eigenvectors = np.linalg.eig(M.T) ind = np.argmax(eigenvalues) # eigenvector of largest eigenvalue is at ind, normalized largest = np.array(eigenvectors[:, ind]).flatten().real norm = largest.sum() return dict(zip(G, map(float, largest / norm))) def _pagerank_scipy( G, alpha=0.85, personalization=None, max_iter=100, tol=1.0e-6, nstart=None, weight="weight", dangling=None, ): """返回图中节点的PageRank值。 PageRank根据图G中入链的结构计算节点的排名。它最初被设计为一种对网页进行排名的算法。 Parameters ---------- G : 图 一个NetworkX图。无向图将被转换为一个有向图,每条无向边对应两条有向边。 alpha : 浮点数, 可选 PageRank的阻尼参数,默认为0.85。 personalization: 字典, 可选 由包含图节点子集及其个性化值的字典组成的“个性化向量”。至少一个个性化值必须非零。如果未指定,节点的个性化值将为零。默认使用均匀分布。 max_iter : 整数, 可选 幂方法特征值求解器中的最大迭代次数。 tol : 浮点数, 可选 用于检查幂方法求解器中收敛性的误差容限。迭代将在达到 ``len(G) * tol`` 的容限后停止。 nstart : 字典, 可选 每个节点的PageRank迭代初始值。 weight : 键, 可选 用作权重的边数据键。如果为None,权重设置为1。 dangling: 字典, 可选 分配给任何“悬挂”节点的出边,即没有出边的节点。字典键是出边指向的节点,字典值是该出边的权重。默认情况下,悬挂节点根据个性化向量(如果未指定则为均匀分布)分配出边。这必须选择以产生不可约的转移矩阵(参见google_matrix下的注释)。通常,悬挂字典与个性化字典相同。 Returns ------- pagerank : 字典 包含节点及其PageRank值的字典 Examples -------- >>> from networkx.algorithms.link_analysis.pagerank_alg import _pagerank_scipy >>> G = nx.DiGraph(nx.path_graph(4)) >>> pr = _pagerank_scipy(G, alpha=0.9) Notes ----- 特征向量计算使用带有SciPy稀疏矩阵表示的幂迭代。 此实现适用于多(有向)图。对于多图,两个节点之间的权重设置为这些节点之间所有边权重的总和。 See Also -------- pagerank Raises ------ PowerIterationFailedConvergence 如果算法在幂迭代方法的指定迭代次数内未收敛到指定容限。 References ---------- .. [1] A. Langville and C. Meyer, "A survey of eigenvector methods of web information retrieval." http://citeseer.ist.psu.edu/713792.html .. [2] Page, Lawrence; Brin, Sergey; Motwani, Rajeev and Winograd, Terry, The PageRank citation ranking: Bringing order to the Web. 1999 http://dbpubs.stanford.edu:8090/pub/showDoc.Fulltext?lang=en&doc=1999-66&format=pdf """ import numpy as np import scipy as sp N = len(G) if N == 0: return {} nodelist = list(G) A = nx.to_scipy_sparse_array(G, nodelist=nodelist, weight=weight, dtype=float) S = A.sum(axis=1) S[S != 0] = 1.0 / S[S != 0] # TODO: csr_array Q = sp.sparse.csr_array(sp.sparse.spdiags(S.T, 0, *A.shape)) A = Q @ A # initial vector if nstart is None: x = np.repeat(1.0 / N, N) else: x = np.array([nstart.get(n, 0) for n in nodelist], dtype=float) x /= x.sum() # Personalization vector if personalization is None: p = np.repeat(1.0 / N, N) else: p = np.array([personalization.get(n, 0) for n in nodelist], dtype=float) if p.sum() == 0: raise ZeroDivisionError p /= p.sum() # Dangling nodes if dangling is None: dangling_weights = p else: # Convert the dangling dictionary into an array in nodelist order dangling_weights = np.array([dangling.get(n, 0) for n in nodelist], dtype=float) dangling_weights /= dangling_weights.sum() is_dangling = np.where(S == 0)[0] # power iteration: make up to max_iter iterations for _ in range(max_iter): xlast = x x = alpha * (x @ A + sum(x[is_dangling]) * dangling_weights) + (1 - alpha) * p # check convergence, l1 norm err = np.absolute(x - xlast).sum() if err < N * tol: return dict(zip(nodelist, map(float, x))) raise nx.PowerIterationFailedConvergence(max_iter)