diff options
author | Dan Schult <dschult@colgate.edu> | 2015-10-21 19:30:42 -0400 |
---|---|---|
committer | Dan Schult <dschult@colgate.edu> | 2015-10-21 19:30:42 -0400 |
commit | 87a620eae4f0afaa9ab9fd86e87e64b40dac3685 (patch) | |
tree | c5cf1b94595369ce3c46c2aad17cc7b23f51ea47 | |
parent | a66a1ef4452ea41d191585d70159a1460264fc95 (diff) | |
parent | 39aad045363999a8a9b40dac97c9c4e673eb8a67 (diff) | |
download | networkx-87a620eae4f0afaa9ab9fd86e87e64b40dac3685.tar.gz |
Merge pull request #1805 from wuhaochen/reciprocity
Implement reciprocity for directed graphs.
-rw-r--r-- | networkx/algorithms/__init__.py | 1 | ||||
-rw-r--r-- | networkx/algorithms/reciprocity.py | 101 |
2 files changed, 102 insertions, 0 deletions
diff --git a/networkx/algorithms/__init__.py b/networkx/algorithms/__init__.py index 67619ab8..5b20896a 100644 --- a/networkx/algorithms/__init__.py +++ b/networkx/algorithms/__init__.py @@ -21,6 +21,7 @@ from networkx.algorithms.mis import * from networkx.algorithms.link_analysis import * from networkx.algorithms.link_prediction import * from networkx.algorithms.operators import * +from networkx.algorithms.reciprocity import * from networkx.algorithms.shortest_paths import * from networkx.algorithms.smetric import * from networkx.algorithms.triads import * diff --git a/networkx/algorithms/reciprocity.py b/networkx/algorithms/reciprocity.py new file mode 100644 index 00000000..67e34631 --- /dev/null +++ b/networkx/algorithms/reciprocity.py @@ -0,0 +1,101 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2015 by +# Haochen Wu <wuhaochen42@gmail.com> +# All rights reserved. +# BSD license. +"""Algorithms to calculate reciprocity in a directed graph.""" +from networkx import NetworkXError +from ..utils import not_implemented_for + +__author__ = """\n""".join(['Haochen Wu <wuhaochen42@gmail.com>']) + +__all__= ['reciprocity','overall_reciprocity'] + +@not_implemented_for('undirected','multigraph') +def reciprocity(G, nodes=None): + """Compute the reciprocity in a directed graph. + + The reciprocity of a directed graph is defined as the ratio + of the number of edges pointing in both directions to the total + number of edges in the graph. + Formally, r = |{(u,v) \in G|(v,u) \in G}| / |{(u,v) \in G}|. + + The reciprocity of a single node u is defined similarly, + it is the ratio of the number of edges in both directions to + the total number of edges attached to node u. + + Parameters + ---------- + G : graph + A networkx directed graph + nodes : container of nodes, optional (default=None, + in such case return the reciprocity of the whole graph.) + Compute reciprocity for nodes in this container. + + Returns + ------- + out : dictionary + Reciprocity keyed by node label. + + Notes + ----- + The reciprocity is not defined for isolated nodes. + In such cases this function will return None. + + """ + # If `nodes` is not specified, calculate the reciprocity of the graph. + if nodes is None: + return overall_reciprocity(G) + + # If `nodes` represents a single node in the graph, return only its + # reciprocity. + if nodes in G: + reciprocity = next(_reciprocity_iter(G,nodes))[1] + if reciprocity is None: + raise NetworkXError('Not defined for isolated nodes.') + else: + return reciprocity + + # Otherwise, `nodes` represents an iterable of nodes, so return a + # dictionary mapping node to its reciprocity. + return dict(_reciprocity_iter(G,nodes)) + +def _reciprocity_iter(G,nodes): + """ Return an iterator of (node, reciprocity). + + """ + n = G.nbunch_iter(nodes) + for node in n: + pred = set(G.predecessors(node)) + succ = set(G.successors(node)) + overlap = pred & succ + n_total = len(pred) + len(succ) + + # Reciprocity is not defined for isolated nodes. + # Return None. + if n_total == 0: + yield (node,None) + else: + reciprocity = 2.0*float(len(overlap))/float(n_total) + yield (node,reciprocity) + +@not_implemented_for('undirected','multigraph') +def overall_reciprocity(G): + """Compute the reciprocity for the whole graph. + + See the doc of reciprocity for the definition. + + Parameters + ---------- + G : graph + A networkx graph + + """ + n_all_edge = G.number_of_edges() + n_overlap_edge = (n_all_edge - G.to_undirected().number_of_edges()) *2 + + if n_all_edge == 0: + raise NetworkXError("Not defined for empty graphs") + + return float(n_overlap_edge)/float(n_all_edge) |