dispersion.py 3.5 KB

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