Freeman’s Segregation Index

Freeman’s Segregation Index (Freeman, 1978; Bojanowski, 2014) measures segregation by comparing the actual number of cross-group ties in a network to what we would expect if the network’s ties were formed completely at random.

To calculate it, we define two variables:

  • \(p\) (Observed cross-group density): The actual number of ties between different groups divided by the total possible number of cross-group ties.

  • \(\pi\) (Expected cross-group density): The overall edge density of the entire graph. In a purely random network, the density of ties between groups would simply equal this overall density.

Using these variables, Freeman’s index is calculated as:

\[Freeman = \frac{\pi - p}{\pi}\]

In Freeman’s case, a random network with the same edge density servers as a null-model.

from netseg import freeman
import igraph as ig 
import matplotlib.pyplot as plt 
from matplotlib.colors import LinearSegmentedColormap, to_hex, Normalize, BoundaryNorm
import random 
import numpy as np 
from time import perf_counter
from mpl_toolkits.axes_grid1 import make_axes_locatable
from matplotlib.cm import ScalarMappable
import matplotlib.patches as mpatches

%config InlineBackend.figure_format = 'retina'

COLORS = [
    '#2C486F',
    '#436796',
    '#5E8FAE',
    '#80BDD6',
    '#B1DDE0',
    "#fdf8e7",
    '#F8E5B2',
    '#F3CF63',
    '#E9A64C',
    '#E3843B',
    '#DA584E'
 ]

def make_symmetric_sbm(p_in, p_out, n_groups, nodes_per_group, membership, **kwargs):
    pref_matrix = [
        [p_in if i == j else p_out for j in range(n_groups)] 
        for i in range(n_groups)
    ]
    block_sizes = [nodes_per_group] * n_groups
    g = ig.Graph.SBM(pref_matrix, block_sizes, **kwargs)
    
    g.vs['membership'] = membership
    
    return g 

Basic Usage

membership= [0 if i < 50 else 1 for i in range(100)]
random.seed(2)
g = make_symmetric_sbm(0.08, 0.004, 2, 50,membership, directed = False)

fig, ax = plt.subplots(figsize = (8,8))
ig.plot(g, 
        vertex_size = 24,
        edge_color = "black",
        vertex_color = [COLORS[2] if i == 0 else COLORS[-3] for i in membership],
        edge_width = 0.3,
        edge_arrow_size = .6,
        layout = g.layout_kamada_kawai(),
        target = ax)


g1 = mpatches.Patch(color = COLORS[2], label = "Group I")
g2 = mpatches.Patch(color = COLORS[-3], label = "Group II")

ax.legend(handles = [g1,g2], loc = "lower right", title = "Nodal Attributes")
plt.show()
freeman_score = freeman("membership",g)
print(freeman_score)
0.8986976744186046

We can generate a random network, since Freeman subtracts a random network with the same edge density, the score should be approximately 0.

g_er = ig.Graph.Erdos_Renyi(100, 0.3)
g_er.vs['membership'] = membership
freeman_random_score = freeman("membership", g_er)
print(freeman_random_score)
-0.0012575250836119878

Multiple Groups

membership_multiple = ["foo"] * 50 + ["bar"] * 50 + ["baz"] * 50
colors_dict = {"foo":3, "bar":9, "baz":6}
random.seed(4)
g_multiple = make_symmetric_sbm(0.2, 0.001, 3, 50, membership_multiple, directed = False)
fig, ax = plt.subplots(figsize = (8,8))
ig.plot(g_multiple, vertex_size = 24, edge_arrow_size = .6, edge_width = .3, layout = g_multiple.layout_kamada_kawai(), vertex_color = [COLORS[colors_dict[i]] for i in membership_multiple],target = ax)

g1 = mpatches.Patch(color = COLORS[3], label = "Group I")
g2 = mpatches.Patch(color = COLORS[6], label = "Group II")
g3 = mpatches.Patch(color = COLORS[9], label = "Group II")

ax.legend(handles = [g1,g2,g3], loc = "lower right", title = "Nodal Attributes")
plt.show()
freeman_multiple = freeman("membership", g_multiple)
print(freeman_multiple)
0.9921164021164021

Example

We use the “UK Faculty” dataset to demonstrate the Freeman’s Segregation Index. Edges indicate personal friendship connections between faculty members at a UK university. We measure the segregation with the nodal attribute “Group”, which represents the school affiliation of each individual. Original dataset can be found here.

COLORS = [
    "#9B4D2E",  
    "#A8952A", 
    "#2A5C4A",
    "#2A415C"]
g_example = ig.Graph.Read_GML('../assets/uk_faculty/ukfaculty.gml')
colors_dict = dict(zip(set(g_example.vs['Group']), COLORS))
fig, ax = plt.subplots(figsize = (8,8))

ig.plot(g_example, layout = g_example.layout_kamada_kawai(),
        vertex_size = 24, target = ax, vertex_color = [colors_dict.get(i) for i in g_example.vs['Group']],
        edge_width = .3)
plt.show()
freeman_score_example = freeman("Group", g_example)
print(freeman_score_example)
0.7246273651555877

References

  • Bojanowski, M., & Corten, R. (2014). Measuring segregation in social networks. Social networks, 39, 14-32.

  • Freeman, L. C. (1978). Segregation in social networks. Sociological Methods & Research, 6(4), 411-429.