Fixed database typo and removed unnecessary class identifier.
This commit is contained in:
parent
00ad49a143
commit
45fb349a7d
5098 changed files with 952558 additions and 85 deletions
278
venv/Lib/site-packages/networkx/algorithms/structuralholes.py
Normal file
278
venv/Lib/site-packages/networkx/algorithms/structuralholes.py
Normal file
|
@ -0,0 +1,278 @@
|
|||
"""Functions for computing measures of structural holes."""
|
||||
|
||||
import networkx as nx
|
||||
|
||||
__all__ = ["constraint", "local_constraint", "effective_size"]
|
||||
|
||||
|
||||
def mutual_weight(G, u, v, weight=None):
|
||||
"""Returns the sum of the weights of the edge from `u` to `v` and
|
||||
the edge from `v` to `u` in `G`.
|
||||
|
||||
`weight` is the edge data key that represents the edge weight. If
|
||||
the specified key is `None` or is not in the edge data for an edge,
|
||||
that edge is assumed to have weight 1.
|
||||
|
||||
Pre-conditions: `u` and `v` must both be in `G`.
|
||||
|
||||
"""
|
||||
try:
|
||||
a_uv = G[u][v].get(weight, 1)
|
||||
except KeyError:
|
||||
a_uv = 0
|
||||
try:
|
||||
a_vu = G[v][u].get(weight, 1)
|
||||
except KeyError:
|
||||
a_vu = 0
|
||||
return a_uv + a_vu
|
||||
|
||||
|
||||
def normalized_mutual_weight(G, u, v, norm=sum, weight=None):
|
||||
"""Returns normalized mutual weight of the edges from `u` to `v`
|
||||
with respect to the mutual weights of the neighbors of `u` in `G`.
|
||||
|
||||
`norm` specifies how the normalization factor is computed. It must
|
||||
be a function that takes a single argument and returns a number.
|
||||
The argument will be an iterable of mutual weights
|
||||
of pairs ``(u, w)``, where ``w`` ranges over each (in- and
|
||||
out-)neighbor of ``u``. Commons values for `normalization` are
|
||||
``sum`` and ``max``.
|
||||
|
||||
`weight` can be ``None`` or a string, if None, all edge weights
|
||||
are considered equal. Otherwise holds the name of the edge
|
||||
attribute used as weight.
|
||||
|
||||
"""
|
||||
scale = norm(mutual_weight(G, u, w, weight) for w in set(nx.all_neighbors(G, u)))
|
||||
return 0 if scale == 0 else mutual_weight(G, u, v, weight) / scale
|
||||
|
||||
|
||||
def effective_size(G, nodes=None, weight=None):
|
||||
r"""Returns the effective size of all nodes in the graph ``G``.
|
||||
|
||||
The *effective size* of a node's ego network is based on the concept
|
||||
of redundancy. A person's ego network has redundancy to the extent
|
||||
that her contacts are connected to each other as well. The
|
||||
nonredundant part of a person's relationships it's the effective
|
||||
size of her ego network [1]_. Formally, the effective size of a
|
||||
node $u$, denoted $e(u)$, is defined by
|
||||
|
||||
.. math::
|
||||
|
||||
e(u) = \sum_{v \in N(u) \setminus \{u\}}
|
||||
\left(1 - \sum_{w \in N(v)} p_{uw} m_{vw}\right)
|
||||
|
||||
where $N(u)$ is the set of neighbors of $u$ and $p_{uw}$ is the
|
||||
normalized mutual weight of the (directed or undirected) edges
|
||||
joining $u$ and $v$, for each vertex $u$ and $v$ [1]_. And $m_{vw}$
|
||||
is the mutual weight of $v$ and $w$ divided by $v$ highest mutual
|
||||
weight with any of its neighbors. The *mutual weight* of $u$ and $v$
|
||||
is the sum of the weights of edges joining them (edge weights are
|
||||
assumed to be one if the graph is unweighted).
|
||||
|
||||
For the case of unweighted and undirected graphs, Borgatti proposed
|
||||
a simplified formula to compute effective size [2]_
|
||||
|
||||
.. math::
|
||||
|
||||
e(u) = n - \frac{2t}{n}
|
||||
|
||||
where `t` is the number of ties in the ego network (not including
|
||||
ties to ego) and `n` is the number of nodes (excluding ego).
|
||||
|
||||
Parameters
|
||||
----------
|
||||
G : NetworkX graph
|
||||
The graph containing ``v``. Directed graphs are treated like
|
||||
undirected graphs when computing neighbors of ``v``.
|
||||
|
||||
nodes : container, optional
|
||||
Container of nodes in the graph ``G`` to compute the effective size.
|
||||
If None, the effective size of every node is computed.
|
||||
|
||||
weight : None or string, optional
|
||||
If None, all edge weights are considered equal.
|
||||
Otherwise holds the name of the edge attribute used as weight.
|
||||
|
||||
Returns
|
||||
-------
|
||||
dict
|
||||
Dictionary with nodes as keys and the effective size of the node as values.
|
||||
|
||||
Notes
|
||||
-----
|
||||
Burt also defined the related concept of *efficiency* of a node's ego
|
||||
network, which is its effective size divided by the degree of that
|
||||
node [1]_. So you can easily compute efficiency:
|
||||
|
||||
>>> G = nx.DiGraph()
|
||||
>>> G.add_edges_from([(0, 1), (0, 2), (1, 0), (2, 1)])
|
||||
>>> esize = nx.effective_size(G)
|
||||
>>> efficiency = {n: v / G.degree(n) for n, v in esize.items()}
|
||||
|
||||
See also
|
||||
--------
|
||||
constraint
|
||||
|
||||
References
|
||||
----------
|
||||
.. [1] Burt, Ronald S.
|
||||
*Structural Holes: The Social Structure of Competition.*
|
||||
Cambridge: Harvard University Press, 1995.
|
||||
|
||||
.. [2] Borgatti, S.
|
||||
"Structural Holes: Unpacking Burt's Redundancy Measures"
|
||||
CONNECTIONS 20(1):35-38.
|
||||
http://www.analytictech.com/connections/v20(1)/holes.htm
|
||||
|
||||
"""
|
||||
|
||||
def redundancy(G, u, v, weight=None):
|
||||
nmw = normalized_mutual_weight
|
||||
r = sum(
|
||||
nmw(G, u, w, weight=weight) * nmw(G, v, w, norm=max, weight=weight)
|
||||
for w in set(nx.all_neighbors(G, u))
|
||||
)
|
||||
return 1 - r
|
||||
|
||||
effective_size = {}
|
||||
if nodes is None:
|
||||
nodes = G
|
||||
# Use Borgatti's simplified formula for unweighted and undirected graphs
|
||||
if not G.is_directed() and weight is None:
|
||||
for v in nodes:
|
||||
# Effective size is not defined for isolated nodes
|
||||
if len(G[v]) == 0:
|
||||
effective_size[v] = float("nan")
|
||||
continue
|
||||
E = nx.ego_graph(G, v, center=False, undirected=True)
|
||||
effective_size[v] = len(E) - (2 * E.size()) / len(E)
|
||||
else:
|
||||
for v in nodes:
|
||||
# Effective size is not defined for isolated nodes
|
||||
if len(G[v]) == 0:
|
||||
effective_size[v] = float("nan")
|
||||
continue
|
||||
effective_size[v] = sum(
|
||||
redundancy(G, v, u, weight) for u in set(nx.all_neighbors(G, v))
|
||||
)
|
||||
return effective_size
|
||||
|
||||
|
||||
def constraint(G, nodes=None, weight=None):
|
||||
r"""Returns the constraint on all nodes in the graph ``G``.
|
||||
|
||||
The *constraint* is a measure of the extent to which a node *v* is
|
||||
invested in those nodes that are themselves invested in the
|
||||
neighbors of *v*. Formally, the *constraint on v*, denoted `c(v)`,
|
||||
is defined by
|
||||
|
||||
.. math::
|
||||
|
||||
c(v) = \sum_{w \in N(v) \setminus \{v\}} \ell(v, w)
|
||||
|
||||
where `N(v)` is the subset of the neighbors of `v` that are either
|
||||
predecessors or successors of `v` and `\ell(v, w)` is the local
|
||||
constraint on `v` with respect to `w` [1]_. For the definition of local
|
||||
constraint, see :func:`local_constraint`.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
G : NetworkX graph
|
||||
The graph containing ``v``. This can be either directed or undirected.
|
||||
|
||||
nodes : container, optional
|
||||
Container of nodes in the graph ``G`` to compute the constraint. If
|
||||
None, the constraint of every node is computed.
|
||||
|
||||
weight : None or string, optional
|
||||
If None, all edge weights are considered equal.
|
||||
Otherwise holds the name of the edge attribute used as weight.
|
||||
|
||||
Returns
|
||||
-------
|
||||
dict
|
||||
Dictionary with nodes as keys and the constraint on the node as values.
|
||||
|
||||
See also
|
||||
--------
|
||||
local_constraint
|
||||
|
||||
References
|
||||
----------
|
||||
.. [1] Burt, Ronald S.
|
||||
"Structural holes and good ideas".
|
||||
American Journal of Sociology (110): 349–399.
|
||||
|
||||
"""
|
||||
if nodes is None:
|
||||
nodes = G
|
||||
constraint = {}
|
||||
for v in nodes:
|
||||
# Constraint is not defined for isolated nodes
|
||||
if len(G[v]) == 0:
|
||||
constraint[v] = float("nan")
|
||||
continue
|
||||
constraint[v] = sum(
|
||||
local_constraint(G, v, n, weight) for n in set(nx.all_neighbors(G, v))
|
||||
)
|
||||
return constraint
|
||||
|
||||
|
||||
def local_constraint(G, u, v, weight=None):
|
||||
r"""Returns the local constraint on the node ``u`` with respect to
|
||||
the node ``v`` in the graph ``G``.
|
||||
|
||||
Formally, the *local constraint on u with respect to v*, denoted
|
||||
$\ell(v)$, is defined by
|
||||
|
||||
.. math::
|
||||
|
||||
\ell(u, v) = \left(p_{uv} + \sum_{w \in N(v)} p_{uw} p{wv}\right)^2,
|
||||
|
||||
where $N(v)$ is the set of neighbors of $v$ and $p_{uv}$ is the
|
||||
normalized mutual weight of the (directed or undirected) edges
|
||||
joining $u$ and $v$, for each vertex $u$ and $v$ [1]_. The *mutual
|
||||
weight* of $u$ and $v$ is the sum of the weights of edges joining
|
||||
them (edge weights are assumed to be one if the graph is
|
||||
unweighted).
|
||||
|
||||
Parameters
|
||||
----------
|
||||
G : NetworkX graph
|
||||
The graph containing ``u`` and ``v``. This can be either
|
||||
directed or undirected.
|
||||
|
||||
u : node
|
||||
A node in the graph ``G``.
|
||||
|
||||
v : node
|
||||
A node in the graph ``G``.
|
||||
|
||||
weight : None or string, optional
|
||||
If None, all edge weights are considered equal.
|
||||
Otherwise holds the name of the edge attribute used as weight.
|
||||
|
||||
Returns
|
||||
-------
|
||||
float
|
||||
The constraint of the node ``v`` in the graph ``G``.
|
||||
|
||||
See also
|
||||
--------
|
||||
constraint
|
||||
|
||||
References
|
||||
----------
|
||||
.. [1] Burt, Ronald S.
|
||||
"Structural holes and good ideas".
|
||||
American Journal of Sociology (110): 349–399.
|
||||
|
||||
"""
|
||||
nmw = normalized_mutual_weight
|
||||
direct = nmw(G, u, v, weight=weight)
|
||||
indirect = sum(
|
||||
nmw(G, u, w, weight=weight) * nmw(G, w, v, weight=weight)
|
||||
for w in set(nx.all_neighbors(G, u))
|
||||
)
|
||||
return (direct + indirect) ** 2
|
Loading…
Add table
Add a link
Reference in a new issue