Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1360 from Scinawa/harmonic
Added Harmonic Centrality Algorithm
- Loading branch information
Showing
4 changed files
with
229 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,22 +1,13 @@ | ||
from networkx.algorithms.centrality.betweenness import * | ||
from networkx.algorithms.centrality.betweenness_subset import * | ||
from networkx.algorithms.centrality.closeness import * | ||
from networkx.algorithms.centrality.current_flow_closeness import * | ||
from networkx.algorithms.centrality.current_flow_betweenness import * | ||
from networkx.algorithms.centrality.current_flow_betweenness_subset import * | ||
from networkx.algorithms.centrality.degree_alg import * | ||
from networkx.algorithms.centrality.dispersion import * | ||
from networkx.algorithms.centrality.eigenvector import * | ||
from networkx.algorithms.centrality.katz import * | ||
from networkx.algorithms.centrality.load import * | ||
from networkx.algorithms.centrality.communicability_alg import * | ||
import networkx.algorithms.centrality.betweenness | ||
import networkx.algorithms.centrality.closeness | ||
import networkx.algorithms.centrality.current_flow_betweenness | ||
import networkx.algorithms.centrality.current_flow_closeness | ||
import networkx.algorithms.centrality.degree_alg | ||
import networkx.algorithms.centrality.dispersion | ||
import networkx.algorithms.centrality.eigenvector | ||
import networkx.algorithms.centrality.load | ||
import networkx.algorithms.centrality.communicability_alg | ||
import networkx.algorithms.centrality.katz | ||
from .betweenness import * | ||
from .betweenness_subset import * | ||
from .closeness import * | ||
from .communicability_alg import * | ||
from .current_flow_closeness import * | ||
from .current_flow_betweenness import * | ||
from .current_flow_betweenness_subset import * | ||
from .degree_alg import * | ||
from .dispersion import * | ||
from .eigenvector import * | ||
from .harmonic import * | ||
from .katz import * | ||
from .load import * |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
""" | ||
Harmonic centrality measure. | ||
""" | ||
# Copyright (C) 2004-2015 by | ||
# Alessandro Luongo | ||
# BSD license. | ||
from __future__ import division | ||
import functools | ||
import networkx as nx | ||
|
||
|
||
__author__ = "\n".join(['Alessandro Luongo (alessandro.luongo@studenti.unimi.it']) | ||
__all__ = ['harmonic_centrality'] | ||
|
||
|
||
def harmonic_centrality(G, distance=None): | ||
r"""Compute harmonic centrality for nodes. | ||
Harmonic centrality [1] of a node `u` is the sum of the reciprocal of the | ||
nonzero shortest paths from all other nodes. | ||
.. math:: | ||
C(u) = \sum_{v=1}^{n-1} \frac{1}{d(v, u)}, | ||
where `d(v, u)` is the shortest-path distance between `v` and `u`, | ||
and `n` is the number of nodes in the graph. | ||
Notice that higher values indicate higher centrality. | ||
Parameters | ||
---------- | ||
G : graph | ||
A NetworkX graph. | ||
distance : edge attribute key, optional (default=None) | ||
Use the specified edge attribute as the edge distance in shortest path | ||
calculations. If `None`, then each edge will have distance equal to 1. | ||
Returns | ||
------- | ||
nodes : dictionary | ||
Dictionary of nodes with harmonic centrality as the value. | ||
See Also | ||
-------- | ||
betweenness_centrality, load_centrality, eigenvector_centrality, | ||
degree_centrality, closeness_centrality | ||
Notes | ||
----- | ||
If the 'distance' keyword is set to an edge attribute key then the | ||
shortest-path length will be computed using Dijkstra's algorithm with | ||
that edge attribute as the edge weight. | ||
References | ||
---------- | ||
.. [1] Boldi, Paolo, and Sebastiano Vigna. "Axioms for centrality." | ||
Internet Mathematics 10.3-4 (2014): 222-262. | ||
""" | ||
|
||
if distance is not None: | ||
# use Dijkstra's algorithm with specified attribute as edge weight | ||
path_length = functools.partial(nx.all_pairs_dijkstra_path_length, | ||
weight=distance) | ||
else: | ||
path_length = nx.all_pairs_shortest_path_length | ||
|
||
nodes = G.nodes() | ||
harmonic_centrality = {} | ||
|
||
if len(G) <= 1: | ||
for singleton in nodes: | ||
harmonic_centrality[singleton] = 0.0 | ||
return harmonic_centrality | ||
|
||
sp = path_length(G.reverse() if G.is_directed() else G) | ||
|
||
for n in nodes: | ||
harmonic_centrality[n] = sum([1/i if i > 0 else 0 | ||
for i in sp[n].values()]) | ||
|
||
return harmonic_centrality | ||
|
||
|
129 changes: 129 additions & 0 deletions
129
networkx/algorithms/centrality/tests/test_harmonic_centrality.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
""" | ||
Tests for degree centrality. | ||
""" | ||
from nose.tools import * | ||
import networkx as nx | ||
from networkx.algorithms.centrality import harmonic_centrality | ||
|
||
class TestClosenessCentrality: | ||
def setUp(self): | ||
self.P3 = nx.path_graph(3) | ||
self.P4 = nx.path_graph(4) | ||
self.K5 = nx.complete_graph(5) | ||
|
||
self.C4 = nx.cycle_graph(4) | ||
self.C5 = nx.cycle_graph(5) | ||
|
||
|
||
self.T = nx.balanced_tree(r=2, h=2) | ||
|
||
self.Gb = nx.DiGraph() | ||
self.Gb.add_edges_from([(0, 1), (0, 2), (0, 4), (2, 1), | ||
(2, 3), (4, 3)]) | ||
|
||
|
||
def test_p3_harmonic(self): | ||
c = harmonic_centrality(self.P3) | ||
d = {0: 1.5, | ||
1: 2, | ||
2: 1.5} | ||
for n in sorted(self.P3): | ||
assert_almost_equal(c[n], d[n], places=3) | ||
|
||
|
||
def test_p4_harmonic(self): | ||
c = harmonic_centrality(self.P4) | ||
d = {0: 1.8333333, | ||
1: 2.5, | ||
2: 2.5, | ||
3: 1.8333333} | ||
for n in sorted(self.P4): | ||
assert_almost_equal(c[n], d[n], places=3) | ||
|
||
|
||
def test_clique_complete(self): | ||
c = harmonic_centrality(self.K5) | ||
d = {0: 4, | ||
1: 4, | ||
2: 4, | ||
3: 4, | ||
4: 4} | ||
for n in sorted(self.P3): | ||
assert_almost_equal(c[n], d[n],places=3) | ||
|
||
|
||
def test_cycle_C4(self): | ||
c = harmonic_centrality(self.C4) | ||
d = {0: 2.5, | ||
1: 2.5, | ||
2: 2.5, | ||
3: 2.5,} | ||
for n in sorted(self.C4): | ||
assert_almost_equal(c[n], d[n], places=3) | ||
|
||
|
||
def test_cycle_C5(self): | ||
c = harmonic_centrality(self.C5) | ||
d={0: 3, | ||
1: 3, | ||
2: 3, | ||
3: 3, | ||
4: 3, | ||
5: 4} | ||
for n in sorted(self.C5): | ||
assert_almost_equal(c[n], d[n], places=3) | ||
|
||
|
||
def test_bal_tree(self): | ||
c = harmonic_centrality(self.T) | ||
d = {0: 4.0, | ||
1: 4.1666, | ||
2: 4.1666, | ||
3: 2.8333, | ||
4: 2.8333, | ||
5: 2.8333, | ||
6: 2.8333} | ||
for n in sorted(self.T): | ||
assert_almost_equal(c[n], d[n], places=3) | ||
|
||
|
||
def test_exampleGraph(self): | ||
c = harmonic_centrality(self.Gb) | ||
d = {0: 0, | ||
1: 2, | ||
2: 1, | ||
3: 2.5, | ||
4: 1} | ||
for n in sorted(self.Gb): | ||
assert_almost_equal(c[n], d[n], places=3) | ||
|
||
|
||
def test_weighted_harmonic(self): | ||
XG = nx.DiGraph() | ||
XG.add_weighted_edges_from([('a','b',10), ('d','c',5), ('a','c',1), | ||
('e','f',2), ('f','c',1), ('a','f',3), | ||
]) | ||
c = harmonic_centrality(XG, distance='weight') | ||
d = {'a': 0, | ||
'b': 0.1, | ||
'c': 2.533, | ||
'd': 0, | ||
'e': 0, | ||
'f': 0.83333} | ||
for n in sorted(XG): | ||
assert_almost_equal(c[n], d[n], places=3) | ||
|
||
|
||
def test_empty(self): | ||
G = nx.DiGraph() | ||
c = harmonic_centrality(G, distance='weight') | ||
d = {} | ||
assert_equal(c, d) | ||
|
||
|
||
def test_singleton(self): | ||
G = nx.DiGraph() | ||
G.add_node(0) | ||
c = harmonic_centrality(G, distance='weight') | ||
d = {0: 0} | ||
assert_equal(c, d) |