143 lines
4.4 KiB
Python
143 lines
4.4 KiB
Python
# -*- coding: utf-8 -*-
|
||
#
|
||
# Copyright (C) 2011 by
|
||
# Jordi Torrents <jtorrents@milnou.net>
|
||
# Aric Hagberg <hagberg@lanl.gov>
|
||
# All rights reserved.
|
||
# BSD license.
|
||
#
|
||
#
|
||
# Authors: Jordi Torrents <jtorrents@milnou.net>
|
||
# Aric Hagberg <hagberg@lanl.gov>
|
||
|
||
from collections import defaultdict
|
||
|
||
import networkx as nx
|
||
|
||
__all__ = ['average_degree_connectivity',
|
||
'k_nearest_neighbors']
|
||
|
||
|
||
def average_degree_connectivity(G, source="in+out", target="in+out",
|
||
nodes=None, weight=None):
|
||
r"""Compute the average degree connectivity of graph.
|
||
|
||
The average degree connectivity is the average nearest neighbor degree of
|
||
nodes with degree k. For weighted graphs, an analogous measure can
|
||
be computed using the weighted average neighbors degree defined in
|
||
[1]_, for a node `i`, as
|
||
|
||
.. math::
|
||
|
||
k_{nn,i}^{w} = \frac{1}{s_i} \sum_{j \in N(i)} w_{ij} k_j
|
||
|
||
where `s_i` is the weighted degree of node `i`,
|
||
`w_{ij}` is the weight of the edge that links `i` and `j`,
|
||
and `N(i)` are the neighbors of node `i`.
|
||
|
||
Parameters
|
||
----------
|
||
G : NetworkX graph
|
||
|
||
source : "in"|"out"|"in+out" (default:"in+out")
|
||
Directed graphs only. Use "in"- or "out"-degree for source node.
|
||
|
||
target : "in"|"out"|"in+out" (default:"in+out"
|
||
Directed graphs only. Use "in"- or "out"-degree for target node.
|
||
|
||
nodes : list or iterable (optional)
|
||
Compute neighbor connectivity for these nodes. The default is all
|
||
nodes.
|
||
|
||
weight : string or None, optional (default=None)
|
||
The edge attribute that holds the numerical value used as a weight.
|
||
If None, then each edge has weight 1.
|
||
|
||
Returns
|
||
-------
|
||
d : dict
|
||
A dictionary keyed by degree k with the value of average connectivity.
|
||
|
||
Raises
|
||
------
|
||
ValueError
|
||
If either `source` or `target` are not one of 'in',
|
||
'out', or 'in+out'.
|
||
|
||
Examples
|
||
--------
|
||
>>> G=nx.path_graph(4)
|
||
>>> G.edges[1, 2]['weight'] = 3
|
||
>>> nx.k_nearest_neighbors(G)
|
||
{1: 2.0, 2: 1.5}
|
||
>>> nx.k_nearest_neighbors(G, weight='weight')
|
||
{1: 2.0, 2: 1.75}
|
||
|
||
See also
|
||
--------
|
||
neighbors_average_degree
|
||
|
||
Notes
|
||
-----
|
||
This algorithm is sometimes called "k nearest neighbors" and is also
|
||
available as `k_nearest_neighbors`.
|
||
|
||
References
|
||
----------
|
||
.. [1] A. Barrat, M. Barthélemy, R. Pastor-Satorras, and A. Vespignani,
|
||
"The architecture of complex weighted networks".
|
||
PNAS 101 (11): 3747–3752 (2004).
|
||
"""
|
||
# First, determine the type of neighbors and the type of degree to use.
|
||
if G.is_directed():
|
||
if source not in ('in', 'out', 'in+out'):
|
||
raise ValueError('source must be one of "in", "out", or "in+out"')
|
||
if target not in ('in', 'out', 'in+out'):
|
||
raise ValueError('target must be one of "in", "out", or "in+out"')
|
||
direction = {'out': G.out_degree,
|
||
'in': G.in_degree,
|
||
'in+out': G.degree}
|
||
neighbor_funcs = {'out': G.successors,
|
||
'in': G.predecessors,
|
||
'in+out': G.neighbors}
|
||
source_degree = direction[source]
|
||
target_degree = direction[target]
|
||
neighbors = neighbor_funcs[source]
|
||
# `reverse` indicates whether to look at the in-edge when
|
||
# computing the weight of an edge.
|
||
reverse = (source == 'in')
|
||
else:
|
||
source_degree = G.degree
|
||
target_degree = G.degree
|
||
neighbors = G.neighbors
|
||
reverse = False
|
||
dsum = defaultdict(int)
|
||
dnorm = defaultdict(int)
|
||
# Check if `source_nodes` is actually a single node in the graph.
|
||
source_nodes = source_degree(nodes)
|
||
if nodes in G:
|
||
source_nodes = [(nodes, source_degree(nodes))]
|
||
for n, k in source_nodes:
|
||
nbrdeg = target_degree(neighbors(n))
|
||
if weight is None:
|
||
s = sum(d for n, d in nbrdeg)
|
||
else: # weight nbr degree by weight of (n,nbr) edge
|
||
if reverse:
|
||
s = sum(G[nbr][n].get(weight, 1) * d for nbr, d in nbrdeg)
|
||
else:
|
||
s = sum(G[n][nbr].get(weight, 1) * d for nbr, d in nbrdeg)
|
||
dnorm[k] += source_degree(n, weight=weight)
|
||
dsum[k] += s
|
||
|
||
# normalize
|
||
dc = {}
|
||
for k, avg in dsum.items():
|
||
dc[k] = avg
|
||
norm = dnorm[k]
|
||
if avg > 0 and norm > 0:
|
||
dc[k] /= norm
|
||
return dc
|
||
|
||
|
||
k_nearest_neighbors = average_degree_connectivity
|