Social Network Models

Summary

Social network analysis in the Statistical Rethinking framework models dyadic relationships between individuals as latent generalized social states. The model captures within-dyad reciprocity and between-dyad variation, enabling inference about sharing behaviour and social structure.

The Problem of Dyadic Data

In social networks, observations come in dyads (pairs of individuals). Key structure:

  • : what A does to/for B (e.g., food shared by A with B)
  • : what B does to/for A
  • These are not independent: reciprocity means and are correlated

Standard regression ignores this dyadic dependence. Social network models treat it explicitly.

Generalized Giving Model (Statistical Rethinking, Lecture 15)

Based on McElreath’s Koster & Leckie-style household food sharing model:

Where the key latent structure is the dyadic giving term :

  • : reciprocity — how strongly giving in one direction predicts giving in return
  • : variance of dyadic effects (heterogeneity in relationship strength)
  • , : generalised giving/receiving rates for each individual (not dyad-specific)

Key insight

By estimating , we can quantify whether relationships are reciprocal (positive ) or one-directional (zero/negative ). This cannot be done with standard regression.

Network as a Latent Variable

The dyadic effects can be visualised as a weighted network — edges between each pair of individuals with weights proportional to the posterior mean of . This gives:

  • Posterior uncertainty over network structure
  • Natural interpretation: the network is a latent variable inferred from observed behaviour, not directly measured

PyMC Sketch

with pm.Model() as network_model:
    # Reciprocity correlation matrix for each dyad
    rho = pm.Beta("rho", 2, 2)
    sigma_g = pm.Exponential("sigma_g", 1)
    cov_dyad = sigma_g**2 * pm.math.stack([[1, rho], [rho, 1]])
 
    # Generalised giving/receiving per individual
    r = pm.Normal("r", 0, 1, shape=(N_individuals, 2))  # [giving, receiving]
 
    # Dyadic effects for each (i, j) pair
    G = pm.MvNormal("G", mu=0, cov=cov_dyad, shape=(N_dyads, 2))
 
    # Likelihood
    log_lambda = alpha + G[dyad_idx, direction] + r[sender_idx, 0] + r[receiver_idx, 1]
    pm.Poisson("y", mu=pm.math.exp(log_lambda), observed=y)

Connections

Source