Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.9/dist-packages/networkx/algorithms/assortativity/neighbor_degree.py: 10%

39 statements  

« prev     ^ index     » next       coverage.py v7.3.2, created at 2023-10-20 07:00 +0000

1import networkx as nx 

2 

3__all__ = ["average_neighbor_degree"] 

4 

5 

6@nx._dispatch(edge_attrs="weight") 

7def average_neighbor_degree(G, source="out", target="out", nodes=None, weight=None): 

8 r"""Returns the average degree of the neighborhood of each node. 

9 

10 In an undirected graph, the neighborhood `N(i)` of node `i` contains the 

11 nodes that are connected to `i` by an edge. 

12 

13 For directed graphs, `N(i)` is defined according to the parameter `source`: 

14 

15 - if source is 'in', then `N(i)` consists of predecessors of node `i`. 

16 - if source is 'out', then `N(i)` consists of successors of node `i`. 

17 - if source is 'in+out', then `N(i)` is both predecessors and successors. 

18 

19 The average neighborhood degree of a node `i` is 

20 

21 .. math:: 

22 

23 k_{nn,i} = \frac{1}{|N(i)|} \sum_{j \in N(i)} k_j 

24 

25 where `N(i)` are the neighbors of node `i` and `k_j` is 

26 the degree of node `j` which belongs to `N(i)`. For weighted 

27 graphs, an analogous measure can be defined [1]_, 

28 

29 .. math:: 

30 

31 k_{nn,i}^{w} = \frac{1}{s_i} \sum_{j \in N(i)} w_{ij} k_j 

32 

33 where `s_i` is the weighted degree of node `i`, `w_{ij}` 

34 is the weight of the edge that links `i` and `j` and 

35 `N(i)` are the neighbors of node `i`. 

36 

37 

38 Parameters 

39 ---------- 

40 G : NetworkX graph 

41 

42 source : string ("in"|"out"|"in+out"), optional (default="out") 

43 Directed graphs only. 

44 Use "in"- or "out"-neighbors of source node. 

45 

46 target : string ("in"|"out"|"in+out"), optional (default="out") 

47 Directed graphs only. 

48 Use "in"- or "out"-degree for target node. 

49 

50 nodes : list or iterable, optional (default=G.nodes) 

51 Compute neighbor degree only for specified nodes. 

52 

53 weight : string or None, optional (default=None) 

54 The edge attribute that holds the numerical value used as a weight. 

55 If None, then each edge has weight 1. 

56 

57 Returns 

58 ------- 

59 d: dict 

60 A dictionary keyed by node to the average degree of its neighbors. 

61 

62 Raises 

63 ------ 

64 NetworkXError 

65 If either `source` or `target` are not one of 'in', 'out', or 'in+out'. 

66 If either `source` or `target` is passed for an undirected graph. 

67 

68 Examples 

69 -------- 

70 >>> G = nx.path_graph(4) 

71 >>> G.edges[0, 1]["weight"] = 5 

72 >>> G.edges[2, 3]["weight"] = 3 

73 

74 >>> nx.average_neighbor_degree(G) 

75 {0: 2.0, 1: 1.5, 2: 1.5, 3: 2.0} 

76 >>> nx.average_neighbor_degree(G, weight="weight") 

77 {0: 2.0, 1: 1.1666666666666667, 2: 1.25, 3: 2.0} 

78 

79 >>> G = nx.DiGraph() 

80 >>> nx.add_path(G, [0, 1, 2, 3]) 

81 >>> nx.average_neighbor_degree(G, source="in", target="in") 

82 {0: 0.0, 1: 0.0, 2: 1.0, 3: 1.0} 

83 

84 >>> nx.average_neighbor_degree(G, source="out", target="out") 

85 {0: 1.0, 1: 1.0, 2: 0.0, 3: 0.0} 

86 

87 See Also 

88 -------- 

89 average_degree_connectivity 

90 

91 References 

92 ---------- 

93 .. [1] A. Barrat, M. Barthélemy, R. Pastor-Satorras, and A. Vespignani, 

94 "The architecture of complex weighted networks". 

95 PNAS 101 (11): 3747–3752 (2004). 

96 """ 

97 if G.is_directed(): 

98 if source == "in": 

99 source_degree = G.in_degree 

100 elif source == "out": 

101 source_degree = G.out_degree 

102 elif source == "in+out": 

103 source_degree = G.degree 

104 else: 

105 raise nx.NetworkXError( 

106 f"source argument {source} must be 'in', 'out' or 'in+out'" 

107 ) 

108 

109 if target == "in": 

110 target_degree = G.in_degree 

111 elif target == "out": 

112 target_degree = G.out_degree 

113 elif target == "in+out": 

114 target_degree = G.degree 

115 else: 

116 raise nx.NetworkXError( 

117 f"target argument {target} must be 'in', 'out' or 'in+out'" 

118 ) 

119 else: 

120 if source != "out" or target != "out": 

121 raise nx.NetworkXError( 

122 f"source and target arguments are only supported for directed graphs" 

123 ) 

124 source_degree = target_degree = G.degree 

125 

126 # precompute target degrees -- should *not* be weighted degree 

127 t_deg = dict(target_degree()) 

128 

129 # Set up both predecessor and successor neighbor dicts leaving empty if not needed 

130 G_P = G_S = {n: {} for n in G} 

131 if G.is_directed(): 

132 # "in" or "in+out" cases: G_P contains predecessors 

133 if "in" in source: 

134 G_P = G.pred 

135 # "out" or "in+out" cases: G_S contains successors 

136 if "out" in source: 

137 G_S = G.succ 

138 else: 

139 # undirected leave G_P empty but G_S is the adjacency 

140 G_S = G.adj 

141 

142 # Main loop: Compute average degree of neighbors 

143 avg = {} 

144 for n, deg in source_degree(nodes, weight=weight): 

145 # handle degree zero average 

146 if deg == 0: 

147 avg[n] = 0.0 

148 continue 

149 

150 # we sum over both G_P and G_S, but one of the two is usually empty. 

151 if weight is None: 

152 avg[n] = ( 

153 sum(t_deg[nbr] for nbr in G_S[n]) + sum(t_deg[nbr] for nbr in G_P[n]) 

154 ) / deg 

155 else: 

156 avg[n] = ( 

157 sum(dd.get(weight, 1) * t_deg[nbr] for nbr, dd in G_S[n].items()) 

158 + sum(dd.get(weight, 1) * t_deg[nbr] for nbr, dd in G_P[n].items()) 

159 ) / deg 

160 return avg