dispersion.py 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. from itertools import combinations
  2. import networkx as nx
  3. __all__ = ["dispersion"]
  4. @nx._dispatchable
  5. def dispersion(G, u=None, v=None, normalized=True, alpha=1.0, b=0.0, c=0.0):
  6. r"""Calculate dispersion between `u` and `v` in `G`.
  7. A link between two actors (`u` and `v`) has a high dispersion when their
  8. mutual ties (`s` and `t`) are not well connected with each other.
  9. Parameters
  10. ----------
  11. G : graph
  12. A NetworkX graph.
  13. u : node, optional
  14. The source for the dispersion score (e.g. ego node of the network).
  15. v : node, optional
  16. The target of the dispersion score if specified.
  17. normalized : bool
  18. If True (default) normalize by the embeddedness of the nodes (u and v).
  19. alpha, b, c : float
  20. Parameters for the normalization procedure. When `normalized` is True,
  21. the dispersion value is normalized by::
  22. result = ((dispersion + b) ** alpha) / (embeddedness + c)
  23. as long as the denominator is nonzero.
  24. Returns
  25. -------
  26. nodes : dictionary
  27. If u (v) is specified, returns a dictionary of nodes with dispersion
  28. score for all "target" ("source") nodes. If neither u nor v is
  29. specified, returns a dictionary of dictionaries for all nodes 'u' in the
  30. graph with a dispersion score for each node 'v'.
  31. Notes
  32. -----
  33. This implementation follows Lars Backstrom and Jon Kleinberg [1]_. Typical
  34. usage would be to run dispersion on the ego network $G_u$ if $u$ were
  35. specified. Running :func:`dispersion` with neither $u$ nor $v$ specified
  36. can take some time to complete.
  37. References
  38. ----------
  39. .. [1] Romantic Partnerships and the Dispersion of Social Ties:
  40. A Network Analysis of Relationship Status on Facebook.
  41. Lars Backstrom, Jon Kleinberg.
  42. https://arxiv.org/pdf/1310.6753v1.pdf
  43. """
  44. def _dispersion(G_u, u, v):
  45. """dispersion for all nodes 'v' in a ego network G_u of node 'u'"""
  46. u_nbrs = set(G_u[u])
  47. ST = {n for n in G_u[v] if n in u_nbrs}
  48. set_uv = {u, v}
  49. # all possible ties of connections that u and b share
  50. possib = combinations(ST, 2)
  51. total = 0
  52. for s, t in possib:
  53. # neighbors of s that are in G_u, not including u and v
  54. nbrs_s = u_nbrs.intersection(G_u[s]) - set_uv
  55. # s and t are not directly connected
  56. if t not in nbrs_s:
  57. # s and t do not share a connection
  58. if nbrs_s.isdisjoint(G_u[t]):
  59. # tick for disp(u, v)
  60. total += 1
  61. # neighbors that u and v share
  62. embeddedness = len(ST)
  63. dispersion_val = total
  64. if normalized:
  65. dispersion_val = (total + b) ** alpha
  66. if embeddedness + c != 0:
  67. dispersion_val /= embeddedness + c
  68. return dispersion_val
  69. if u is None:
  70. # v and u are not specified
  71. if v is None:
  72. results = {n: {} for n in G}
  73. for u in G:
  74. for v in G[u]:
  75. results[u][v] = _dispersion(G, u, v)
  76. # u is not specified, but v is
  77. else:
  78. results = dict.fromkeys(G[v], {})
  79. for u in G[v]:
  80. results[u] = _dispersion(G, v, u)
  81. else:
  82. # u is specified with no target v
  83. if v is None:
  84. results = dict.fromkeys(G[u], {})
  85. for v in G[u]:
  86. results[v] = _dispersion(G, u, v)
  87. # both u and v are specified
  88. else:
  89. results = _dispersion(G, u, v)
  90. return results