diff options
-rw-r--r-- | networkx/algorithms/assortativity/neighbor_degree.py | 74 | ||||
-rw-r--r-- | networkx/algorithms/assortativity/tests/test_neighbor_degree.py | 27 |
2 files changed, 57 insertions, 44 deletions
diff --git a/networkx/algorithms/assortativity/neighbor_degree.py b/networkx/algorithms/assortativity/neighbor_degree.py index 84dffd8f..3a9ed8d5 100644 --- a/networkx/algorithms/assortativity/neighbor_degree.py +++ b/networkx/algorithms/assortativity/neighbor_degree.py @@ -1,23 +1,6 @@ __all__ = ["average_neighbor_degree"] -def _average_nbr_deg(G, source_degree, target_degree, nodes=None, weight=None): - # average degree of neighbors - avg = {} - for n, deg in source_degree(nodes, weight=weight): - # normalize but not by zero degree - if deg == 0: - deg = 1 - nbrdeg = target_degree(G[n]) - if weight is None: - avg[n] = sum(d for n, d in nbrdeg) / float(deg) - else: - avg[n] = sum((G[n][nbr].get(weight, 1) * d for nbr, d in nbrdeg)) / float( - deg - ) - return avg - - def average_neighbor_degree(G, source="out", target="out", nodes=None, weight=None): r"""Returns the average degree of the neighborhood of each node. @@ -44,11 +27,11 @@ def average_neighbor_degree(G, source="out", target="out", nodes=None, weight=No ---------- G : NetworkX graph - source : string ("in"|"out") + source : string ("in"|"out"|"in+out") Directed graphs only. Use "in"- or "out"-degree for source node. - target : string ("in"|"out") + target : string ("in"|"out"|"in+out") Directed graphs only. Use "in"- or "out"-degree for target node. @@ -79,7 +62,7 @@ def average_neighbor_degree(G, source="out", target="out", nodes=None, weight=No >>> G = nx.DiGraph() >>> nx.add_path(G, [0, 1, 2, 3]) >>> nx.average_neighbor_degree(G, source="in", target="in") - {0: 1.0, 1: 1.0, 2: 1.0, 3: 0.0} + {0: 0.0, 1: 1.0, 2: 1.0, 3: 0.0} >>> nx.average_neighbor_degree(G, source="out", target="out") {0: 1.0, 1: 1.0, 2: 0.0, 3: 0.0} @@ -102,21 +85,36 @@ def average_neighbor_degree(G, source="out", target="out", nodes=None, weight=No source_degree = G.degree target_degree = G.degree if G.is_directed(): - direction = {"out": G.out_degree, "in": G.in_degree} - source_degree = direction[source] - target_degree = direction[target] - return _average_nbr_deg(G, source_degree, target_degree, nodes=nodes, weight=weight) - - -# obsolete -# def average_neighbor_in_degree(G, nodes=None, weight=None): -# if not G.is_directed(): -# raise nx.NetworkXError("Not defined for undirected graphs.") -# return _average_nbr_deg(G, G.in_degree, G.in_degree, nodes, weight) -# average_neighbor_in_degree.__doc__=average_neighbor_degree.__doc__ - -# def average_neighbor_out_degree(G, nodes=None, weight=None): -# if not G.is_directed(): -# raise nx.NetworkXError("Not defined for undirected graphs.") -# return _average_nbr_deg(G, G.out_degree, G.out_degree, nodes, weight) -# average_neighbor_out_degree.__doc__=average_neighbor_degree.__doc__ + if source == "in": + source_degree = G.in_degree + elif source == "out": + source_degree = G.out_degree + elif source != "in+out": + raise nx.NetworkXError( + f"source argument {source} must be 'in', 'out' or 'in+out'" + ) + + if target == "in": + target_degree = G.in_degree + elif target == "out": + target_degree = G.out_degree + elif target != "in+out": + raise nx.NetworkXError( + f"target argument {target} must be 'in', 'out' or 'in+out'" + ) + + # precompute target degrees -- should *not* be weighted degree + tgt_deg = dict(target_degree()) + # average degree of neighbors + avg = {} + for n, deg in source_degree(nodes, weight=weight): + # normalize but not by zero degree + if deg == 0: + avg[n] = 0.0 + continue + G_n = G[n] + if weight is None: + avg[n] = sum(tgt_deg[nbr] for nbr in G_n) / deg + else: + avg[n] = sum(G_n[nbr].get(weight, 1) * tgt_deg[nbr] for nbr in G_n) / deg + return avg diff --git a/networkx/algorithms/assortativity/tests/test_neighbor_degree.py b/networkx/algorithms/assortativity/tests/test_neighbor_degree.py index 65827da1..66d39b9a 100644 --- a/networkx/algorithms/assortativity/tests/test_neighbor_degree.py +++ b/networkx/algorithms/assortativity/tests/test_neighbor_degree.py @@ -13,13 +13,15 @@ class TestAverageNeighbor: nd = nx.average_neighbor_degree(D) assert nd == answer - D = G.to_directed() + D = nx.DiGraph(G.edges(data=True)) nd = nx.average_neighbor_degree(D) - assert nd == answer - - D = G.to_directed() - nd = nx.average_neighbor_degree(D, source="in", target="in") - assert nd == answer + assert nd == {0: 1, 1: 1, 2: 0, 3: 0} + nd = nx.average_neighbor_degree(D, "in", "out") + assert nd == {0: 0, 1: 1, 2: 0, 3: 0} + nd = nx.average_neighbor_degree(D, "out", "in") + assert nd == {0: 1, 1: 1, 2: 1, 3: 0} + nd = nx.average_neighbor_degree(D, "in", "in") + assert nd == {0: 0, 1: 1, 2: 1, 3: 0} def test_degree_p4_weighted(self): G = nx.path_graph(4) @@ -32,6 +34,19 @@ class TestAverageNeighbor: nd = nx.average_neighbor_degree(D, weight="weight") assert nd == answer + D = nx.DiGraph(G.edges(data=True)) + print(D.edges(data=True)) + nd = nx.average_neighbor_degree(D, weight="weight") + assert nd == {0: 1, 1: 1, 2: 0, 3: 0} + nd = nx.average_neighbor_degree(D, "out", "out", weight="weight") + assert nd == {0: 1, 1: 1, 2: 0, 3: 0} + nd = nx.average_neighbor_degree(D, "in", "in", weight="weight") + assert nd == {0: 0, 1: 4, 2: 0.25, 3: 0} + nd = nx.average_neighbor_degree(D, "in", "out", weight="weight") + assert nd == {0: 0, 1: 4, 2: 0, 3: 0} + nd = nx.average_neighbor_degree(D, "out", "in", weight="weight") + assert nd == {0: 1, 1: 1, 2: 1, 3: 0} + D = G.to_directed() nd = nx.average_neighbor_degree(D, weight="weight") assert nd == answer |