Installation
The core-periphery implementations are available in Python on Github.
pip install git+https://github.com/ryanjgallagher/core_periphery_sbm
Running Core-Periphery Models
The models can be run in Python with any NetworkX graph. To infer a hub-and-spoke structure:
import networkx as nx
from core_periphery_sbm import core_periphery as cp
# Load Les Mis graph from NetworkX
G = nx.les_miserables_graph()
# Initialize hub-and-spoke model and infer structure
hubspoke = cp.HubSpokeCorePeriphery(n_gibbs=100, n_mcmc=10*len(G))
hubspoke.infer(G)
Similarly, we can infer a layered structure with n_layers
:
layered = cp.LayeredCorePeriphery(n_layers=3, n_gibbs=100, n_mcmc=10*len(G))
layered.infer(G)
The models are inferred through an MCMC-within-Gibbs sampling procedure. There are n_gibbs
samples that are taken, and during each Gibbs sample, an MCMC chain of n_mcmc
steps is run on the labels of the network.
From the Gibbs samples, we can infer the core-periphery assignment of each node. Lower indices indicate more core positions. For example, in the hub-and-spoke model, 0 indicates the core and 1 indicates the periphery. In the layered model, 0 is the innermost layer.
# Get core and periphery assignments from hub-and-spoke model
node2label_hs = hubspoke.get_labels(last_n_samples=50)
# Get layer assignments from the layered model
node2label_l = layered.get_labels(last_n_samples=50)
Core-Periphery Model Selection
Given core-periphery labels inferred from the hub-and-spoke and layered models, we want to determine which partition best describes the core-periphery structure of a network. We can do this by comparing the description length of the models. The smaller the description length, the better the model fit. We can approximate the description length for each core-periphery model using n_samples
:
from core_periphery_sbm import model_fit as mf
# Get description length of hub-and-spoke model
inf_labels_hs = hubspoke.get_labels(last_n_samples=50, prob=False, return_dict=False)
mdl_hubspoke = mf.mdl_hubspoke(G, inf_labels_hs, n_samples=100000)
# Get the description length of layered model
inf_labels_l = layered.get_labels(last_n_samples=50, prob=False, return_dict=False)
mdl_layered = mf.mdl_layered(G, inf_labels_l, n_layers=3, n_samples=100000)