Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add assortativity module #122

Merged
merged 19 commits into from
Jun 14, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
response to PR
  • Loading branch information
nwlandry committed Jun 14, 2022
commit 4f2ea71bc8e910eb9e23a153b4936763542eb2da
23 changes: 12 additions & 11 deletions tests/algorithms/test_assortativity.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,14 @@ def test_dynamical_assortativity(edgelist1, edgelist6):

def test_degree_assortativity(edgelist1, edgelist6):
H1 = xgi.Hypergraph(edgelist1)
assert -1 <= xgi.degree_assortativity(H1, type="uniform") <= 1
assert -1 <= xgi.degree_assortativity(H1, type="top-2") <= 1
assert -1 <= xgi.degree_assortativity(H1, type="top-bottom") <= 1
assert -1 <= xgi.degree_assortativity(H1, kind="uniform") <= 1
assert -1 <= xgi.degree_assortativity(H1, kind="top-2") <= 1
assert -1 <= xgi.degree_assortativity(H1, kind="top-bottom") <= 1

H2 = xgi.Hypergraph(edgelist6)
assert -1 <= xgi.degree_assortativity(H2, type="uniform") <= 1
assert -1 <= xgi.degree_assortativity(H2, type="top-2") <= 1
assert -1 <= xgi.degree_assortativity(H2, type="top-bottom") <= 1
assert -1 <= xgi.degree_assortativity(H2, kind="uniform") <= 1
assert -1 <= xgi.degree_assortativity(H2, kind="top-2") <= 1
assert -1 <= xgi.degree_assortativity(H2, kind="top-bottom") <= 1


def test_choose_degrees(edgelist1, edgelist6):
Expand All @@ -47,14 +47,15 @@ def test_choose_degrees(edgelist1, edgelist6):
choose_degrees(e, k)

e = H1.edges.members(0)
assert np.all(choose_degrees(e, k) == 1)
assert np.all(np.array(choose_degrees(e, k)) == 1)


e = H1.edges.members(3)
assert set(choose_degrees(e, k, type="top-2")) == {1, 2}
assert set(choose_degrees(e, k, type="top-bottom")) == {1, 2}
assert set(choose_degrees(e, k, kind="top-2")) == {1, 2}
assert set(choose_degrees(e, k, kind="top-bottom")) == {1, 2}

H2 = xgi.Hypergraph(edgelist6)
e = H2.edges.members(2)
k = H2.degree()
assert set(choose_degrees(e, k, type="top-2")) == {2, 3}
assert set(choose_degrees(e, k, type="top-bottom")) == {1, 3}
assert set(choose_degrees(e, k, kind="top-2")) == {2, 3}
assert set(choose_degrees(e, k, kind="top-bottom")) == {1, 3}
2 changes: 1 addition & 1 deletion xgi/algorithms/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from xgi.algorithms import assortativity, connected
from . import assortativity, connected

from .assortativity import *
from .connected import *
35 changes: 15 additions & 20 deletions xgi/algorithms/assortativity.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ def dynamical_assortativity(H):
raise XGIError("Hypergraph must contain nodes and edges!")

degs = H.degree()
k1 = np.mean([degs[n] for n in H.nodes])
k2 = np.mean([degs[n] ** 2 for n in H.nodes])
k1 = np.mean(list(degs.values()))
k2 = np.mean(np.power(list(degs.values()), 2))
kk1 = np.mean(
[
degs[n1] * degs[n2]
Expand All @@ -56,14 +56,14 @@ def dynamical_assortativity(H):
return kk1 * k1**2 / k2**2 - 1


def degree_assortativity(H, type="uniform", exact=False, num_samples=1000):
def degree_assortativity(H, kind="uniform", exact=False, num_samples=1000):
"""Computes the degree assortativity of a hypergraph

Parameters
----------
H : Hypergraph
The hypergraph of interest
type : str, default: "uniform"
kind : str, default: "uniform"
the type of degree assortativity. valid choices are
"uniform", "top-2", and "top-bottom".
exact : bool, default: False
Expand All @@ -87,23 +87,17 @@ def degree_assortativity(H, type="uniform", exact=False, num_samples=1000):
degs = H.degree()
if exact:
k1k2 = [
choose_degrees(e, degs, type)
choose_degrees(H.edges.members(e), degs, kind)
for e in H.edges
if len(H.edges.members(e)) > 1
]
else:
edges = list([e for e in H.edges if len(H.edges.members(e)) > 1])
k1k2 = list()

samples = 0
while samples < num_samples:
e = random.choice(edges)
k1k2.append(choose_degrees(H.edges.members(e), degs, type))
samples += 1
edges = [e for e in H.edges if len(H.edges.members(e)) > 1]
k1k2 = [choose_degrees(H.edges.members(random.choice(edges)), degs, kind) for _ in range(num_samples)]
return np.corrcoef(np.array(k1k2).T)[0, 1]


def choose_degrees(e, k, type="uniform"):
def choose_degrees(e, k, kind="uniform"):
"""Choose the degrees of two nodes in a hyperedge.

Parameters
Expand All @@ -112,8 +106,9 @@ def choose_degrees(e, k, type="uniform"):
the members in a hyperedge
k : dict
the degrees where keys are node IDs and values are degrees
type : str, default: "uniform"
the type of degree assortativity
kind : str, default: "uniform"
the type of degree assortativity, options are
"uniform", "top-2", and "top-bottom".

Returns
-------
Expand All @@ -133,19 +128,19 @@ def choose_degrees(e, k, type="uniform"):
DOI: 10.1093/comnet/cnaa018
"""
if len(e) > 1:
if type == "uniform":
if kind == "uniform":
i = np.random.randint(len(e))
j = i
while i == j:
j = np.random.randint(len(e))
return np.array([k[e[i]], k[e[j]]])
return (k[e[i]], k[e[j]])

elif type == "top-2":
elif kind == "top-2":
degs = sorted([k[i] for i in e])[-2:]
random.shuffle(degs)
return degs

elif type == "top-bottom":
elif kind == "top-bottom":
degs = sorted([k[i] for i in e])[:: len(e) - 1]
nwlandry marked this conversation as resolved.
Show resolved Hide resolved
random.shuffle(degs)
return degs
Expand Down