blob: 28e0013ee3cc10eca09b9a4e75dda673eb7ec93d [file] [log] [blame]
"""
Eigenvector centrality.
"""
# Copyright (C) 2004-2011 by
# Aric Hagberg <hagberg@lanl.gov>
# Dan Schult <dschult@colgate.edu>
# Pieter Swart <swart@lanl.gov>
# All rights reserved.
# BSD license.
import networkx as nx
__author__ = "\n".join(['Aric Hagberg (hagberg@lanl.gov)',
'Pieter Swart (swart@lanl.gov)',
'Sasha Gutfraind (ag362@cornell.edu)'])
__all__ = ['eigenvector_centrality',
'eigenvector_centrality_numpy']
def eigenvector_centrality(G,max_iter=100,tol=1.0e-6,nstart=None):
"""Compute the eigenvector centrality for the graph G.
Uses the power method to find the eigenvector for the
largest eigenvalue of the adjacency matrix of G.
Parameters
----------
G : graph
A networkx graph
max_iter : interger, optional
Maximum number of iterations in power method.
tol : float, optional
Error tolerance used to check convergence in power method iteration.
nstart : dictionary, optional
Starting value of eigenvector iteration for each node.
Returns
-------
nodes : dictionary
Dictionary of nodes with eigenvector centrality as the value.
Examples
--------
>>> G=nx.path_graph(4)
>>> centrality=nx.eigenvector_centrality(G)
>>> print(['%s %0.2f'%(node,centrality[node]) for node in centrality])
['0 0.37', '1 0.60', '2 0.60', '3 0.37']
Notes
------
The eigenvector calculation is done by the power iteration method
and has no guarantee of convergence. The iteration will stop
after max_iter iterations or an error tolerance of
number_of_nodes(G)*tol has been reached.
For directed graphs this is "right" eigevector centrality. For
"left" eigenvector centrality, first reverse the graph with
G.reverse().
See Also
--------
eigenvector_centrality_numpy
pagerank
hits
"""
from math import sqrt
if type(G) == nx.MultiGraph or type(G) == nx.MultiDiGraph:
raise nx.NetworkXException("Not defined for multigraphs.")
if len(G)==0:
raise nx.NetworkXException("Empty graph.")
if nstart is None:
# choose starting vector with entries of 1/len(G)
x=dict([(n,1.0/len(G)) for n in G])
else:
x=nstart
# normalize starting vector
s=1.0/sum(x.values())
for k in x: x[k]*=s
nnodes=G.number_of_nodes()
# make up to max_iter iterations
for i in range(max_iter):
xlast=x
x=dict.fromkeys(xlast, 0)
# do the multiplication y=Ax
for n in x:
for nbr in G[n]:
x[n]+=xlast[nbr]*G[n][nbr].get('weight',1)
# normalize vector
try:
s=1.0/sqrt(sum(v**2 for v in x.values()))
# this should never be zero?
except ZeroDivisionError:
s=1.0
for n in x: x[n]*=s
# check convergence
err=sum([abs(x[n]-xlast[n]) for n in x])
if err < nnodes*tol:
return x
raise nx.NetworkXError("""eigenvector_centrality():
power iteration failed to converge in %d iterations."%(i+1))""")
def eigenvector_centrality_numpy(G):
"""Compute the eigenvector centrality for the graph G.
Parameters
----------
G : graph
A networkx graph
Returns
-------
nodes : dictionary
Dictionary of nodes with eigenvector centrality as the value.
Examples
--------
>>> G=nx.path_graph(4)
>>> centrality=nx.eigenvector_centrality_numpy(G)
>>> print(['%s %0.2f'%(node,centrality[node]) for node in centrality])
['0 0.37', '1 0.60', '2 0.60', '3 0.37']
Notes
------
This algorithm uses the NumPy eigenvalue solver.
For directed graphs this is "right" eigevector centrality. For
"left" eigenvector centrality, first reverse the graph with
G.reverse().
See Also
--------
eigenvector_centrality
pagerank
hits
"""
try:
import numpy as np
except ImportError:
raise ImportError('Requires NumPy: http://scipy.org/')
if type(G) == nx.MultiGraph or type(G) == nx.MultiDiGraph:
raise nx.NetworkXException('Not defined for multigraphs.')
if len(G)==0:
raise nx.NetworkXException('Empty graph.')
A=nx.adj_matrix(G,nodelist=G.nodes())
eigenvalues,eigenvectors=np.linalg.eig(A)
# eigenvalue indices in reverse sorted order
ind=eigenvalues.argsort()[::-1]
# eigenvector of largest eigenvalue at ind[0], normalized
largest=np.array(eigenvectors[:,ind[0]]).flatten().real
norm=np.sign(largest.sum())*np.linalg.norm(largest)
centrality=dict(zip(G,map(float,largest/norm)))
return centrality
# fixture for nose tests
def setup_module(module):
from nose import SkipTest
try:
import numpy
import numpy.linalg
except:
raise SkipTest("numpy not available")