Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.9/dist-packages/networkx/algorithms/centrality/betweenness_subset.py: 16%

83 statements  

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

1"""Betweenness centrality measures for subsets of nodes.""" 

2import networkx as nx 

3from networkx.algorithms.centrality.betweenness import ( 

4 _add_edge_keys, 

5) 

6from networkx.algorithms.centrality.betweenness import ( 

7 _single_source_dijkstra_path_basic as dijkstra, 

8) 

9from networkx.algorithms.centrality.betweenness import ( 

10 _single_source_shortest_path_basic as shortest_path, 

11) 

12 

13__all__ = [ 

14 "betweenness_centrality_subset", 

15 "edge_betweenness_centrality_subset", 

16] 

17 

18 

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

20def betweenness_centrality_subset(G, sources, targets, normalized=False, weight=None): 

21 r"""Compute betweenness centrality for a subset of nodes. 

22 

23 .. math:: 

24 

25 c_B(v) =\sum_{s\in S, t \in T} \frac{\sigma(s, t|v)}{\sigma(s, t)} 

26 

27 where $S$ is the set of sources, $T$ is the set of targets, 

28 $\sigma(s, t)$ is the number of shortest $(s, t)$-paths, 

29 and $\sigma(s, t|v)$ is the number of those paths 

30 passing through some node $v$ other than $s, t$. 

31 If $s = t$, $\sigma(s, t) = 1$, 

32 and if $v \in {s, t}$, $\sigma(s, t|v) = 0$ [2]_. 

33 

34 

35 Parameters 

36 ---------- 

37 G : graph 

38 A NetworkX graph. 

39 

40 sources: list of nodes 

41 Nodes to use as sources for shortest paths in betweenness 

42 

43 targets: list of nodes 

44 Nodes to use as targets for shortest paths in betweenness 

45 

46 normalized : bool, optional 

47 If True the betweenness values are normalized by $2/((n-1)(n-2))$ 

48 for graphs, and $1/((n-1)(n-2))$ for directed graphs where $n$ 

49 is the number of nodes in G. 

50 

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

52 If None, all edge weights are considered equal. 

53 Otherwise holds the name of the edge attribute used as weight. 

54 Weights are used to calculate weighted shortest paths, so they are 

55 interpreted as distances. 

56 

57 Returns 

58 ------- 

59 nodes : dictionary 

60 Dictionary of nodes with betweenness centrality as the value. 

61 

62 See Also 

63 -------- 

64 edge_betweenness_centrality 

65 load_centrality 

66 

67 Notes 

68 ----- 

69 The basic algorithm is from [1]_. 

70 

71 For weighted graphs the edge weights must be greater than zero. 

72 Zero edge weights can produce an infinite number of equal length 

73 paths between pairs of nodes. 

74 

75 The normalization might seem a little strange but it is 

76 designed to make betweenness_centrality(G) be the same as 

77 betweenness_centrality_subset(G,sources=G.nodes(),targets=G.nodes()). 

78 

79 The total number of paths between source and target is counted 

80 differently for directed and undirected graphs. Directed paths 

81 are easy to count. Undirected paths are tricky: should a path 

82 from "u" to "v" count as 1 undirected path or as 2 directed paths? 

83 

84 For betweenness_centrality we report the number of undirected 

85 paths when G is undirected. 

86 

87 For betweenness_centrality_subset the reporting is different. 

88 If the source and target subsets are the same, then we want 

89 to count undirected paths. But if the source and target subsets 

90 differ -- for example, if sources is {0} and targets is {1}, 

91 then we are only counting the paths in one direction. They are 

92 undirected paths but we are counting them in a directed way. 

93 To count them as undirected paths, each should count as half a path. 

94 

95 References 

96 ---------- 

97 .. [1] Ulrik Brandes, A Faster Algorithm for Betweenness Centrality. 

98 Journal of Mathematical Sociology 25(2):163-177, 2001. 

99 https://doi.org/10.1080/0022250X.2001.9990249 

100 .. [2] Ulrik Brandes: On Variants of Shortest-Path Betweenness 

101 Centrality and their Generic Computation. 

102 Social Networks 30(2):136-145, 2008. 

103 https://doi.org/10.1016/j.socnet.2007.11.001 

104 """ 

105 b = dict.fromkeys(G, 0.0) # b[v]=0 for v in G 

106 for s in sources: 

107 # single source shortest paths 

108 if weight is None: # use BFS 

109 S, P, sigma, _ = shortest_path(G, s) 

110 else: # use Dijkstra's algorithm 

111 S, P, sigma, _ = dijkstra(G, s, weight) 

112 b = _accumulate_subset(b, S, P, sigma, s, targets) 

113 b = _rescale(b, len(G), normalized=normalized, directed=G.is_directed()) 

114 return b 

115 

116 

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

118def edge_betweenness_centrality_subset( 

119 G, sources, targets, normalized=False, weight=None 

120): 

121 r"""Compute betweenness centrality for edges for a subset of nodes. 

122 

123 .. math:: 

124 

125 c_B(v) =\sum_{s\in S,t \in T} \frac{\sigma(s, t|e)}{\sigma(s, t)} 

126 

127 where $S$ is the set of sources, $T$ is the set of targets, 

128 $\sigma(s, t)$ is the number of shortest $(s, t)$-paths, 

129 and $\sigma(s, t|e)$ is the number of those paths 

130 passing through edge $e$ [2]_. 

131 

132 Parameters 

133 ---------- 

134 G : graph 

135 A networkx graph. 

136 

137 sources: list of nodes 

138 Nodes to use as sources for shortest paths in betweenness 

139 

140 targets: list of nodes 

141 Nodes to use as targets for shortest paths in betweenness 

142 

143 normalized : bool, optional 

144 If True the betweenness values are normalized by `2/(n(n-1))` 

145 for graphs, and `1/(n(n-1))` for directed graphs where `n` 

146 is the number of nodes in G. 

147 

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

149 If None, all edge weights are considered equal. 

150 Otherwise holds the name of the edge attribute used as weight. 

151 Weights are used to calculate weighted shortest paths, so they are 

152 interpreted as distances. 

153 

154 Returns 

155 ------- 

156 edges : dictionary 

157 Dictionary of edges with Betweenness centrality as the value. 

158 

159 See Also 

160 -------- 

161 betweenness_centrality 

162 edge_load 

163 

164 Notes 

165 ----- 

166 The basic algorithm is from [1]_. 

167 

168 For weighted graphs the edge weights must be greater than zero. 

169 Zero edge weights can produce an infinite number of equal length 

170 paths between pairs of nodes. 

171 

172 The normalization might seem a little strange but it is the same 

173 as in edge_betweenness_centrality() and is designed to make 

174 edge_betweenness_centrality(G) be the same as 

175 edge_betweenness_centrality_subset(G,sources=G.nodes(),targets=G.nodes()). 

176 

177 References 

178 ---------- 

179 .. [1] Ulrik Brandes, A Faster Algorithm for Betweenness Centrality. 

180 Journal of Mathematical Sociology 25(2):163-177, 2001. 

181 https://doi.org/10.1080/0022250X.2001.9990249 

182 .. [2] Ulrik Brandes: On Variants of Shortest-Path Betweenness 

183 Centrality and their Generic Computation. 

184 Social Networks 30(2):136-145, 2008. 

185 https://doi.org/10.1016/j.socnet.2007.11.001 

186 """ 

187 b = dict.fromkeys(G, 0.0) # b[v]=0 for v in G 

188 b.update(dict.fromkeys(G.edges(), 0.0)) # b[e] for e in G.edges() 

189 for s in sources: 

190 # single source shortest paths 

191 if weight is None: # use BFS 

192 S, P, sigma, _ = shortest_path(G, s) 

193 else: # use Dijkstra's algorithm 

194 S, P, sigma, _ = dijkstra(G, s, weight) 

195 b = _accumulate_edges_subset(b, S, P, sigma, s, targets) 

196 for n in G: # remove nodes to only return edges 

197 del b[n] 

198 b = _rescale_e(b, len(G), normalized=normalized, directed=G.is_directed()) 

199 if G.is_multigraph(): 

200 b = _add_edge_keys(G, b, weight=weight) 

201 return b 

202 

203 

204def _accumulate_subset(betweenness, S, P, sigma, s, targets): 

205 delta = dict.fromkeys(S, 0.0) 

206 target_set = set(targets) - {s} 

207 while S: 

208 w = S.pop() 

209 if w in target_set: 

210 coeff = (delta[w] + 1.0) / sigma[w] 

211 else: 

212 coeff = delta[w] / sigma[w] 

213 for v in P[w]: 

214 delta[v] += sigma[v] * coeff 

215 if w != s: 

216 betweenness[w] += delta[w] 

217 return betweenness 

218 

219 

220def _accumulate_edges_subset(betweenness, S, P, sigma, s, targets): 

221 """edge_betweenness_centrality_subset helper.""" 

222 delta = dict.fromkeys(S, 0) 

223 target_set = set(targets) 

224 while S: 

225 w = S.pop() 

226 for v in P[w]: 

227 if w in target_set: 

228 c = (sigma[v] / sigma[w]) * (1.0 + delta[w]) 

229 else: 

230 c = delta[w] / len(P[w]) 

231 if (v, w) not in betweenness: 

232 betweenness[(w, v)] += c 

233 else: 

234 betweenness[(v, w)] += c 

235 delta[v] += c 

236 if w != s: 

237 betweenness[w] += delta[w] 

238 return betweenness 

239 

240 

241def _rescale(betweenness, n, normalized, directed=False): 

242 """betweenness_centrality_subset helper.""" 

243 if normalized: 

244 if n <= 2: 

245 scale = None # no normalization b=0 for all nodes 

246 else: 

247 scale = 1.0 / ((n - 1) * (n - 2)) 

248 else: # rescale by 2 for undirected graphs 

249 if not directed: 

250 scale = 0.5 

251 else: 

252 scale = None 

253 if scale is not None: 

254 for v in betweenness: 

255 betweenness[v] *= scale 

256 return betweenness 

257 

258 

259def _rescale_e(betweenness, n, normalized, directed=False): 

260 """edge_betweenness_centrality_subset helper.""" 

261 if normalized: 

262 if n <= 1: 

263 scale = None # no normalization b=0 for all nodes 

264 else: 

265 scale = 1.0 / (n * (n - 1)) 

266 else: # rescale by 2 for undirected graphs 

267 if not directed: 

268 scale = 0.5 

269 else: 

270 scale = None 

271 if scale is not None: 

272 for v in betweenness: 

273 betweenness[v] *= scale 

274 return betweenness