Chapter 8 — Applying computational methods

Networks, simulation, prediction, and embeddings

Chapter 8 runs the three computational capacities and four epistemic purposes from Chapter 7 over the data you have already built. This page carries setup notes and library pointers for each exercise.

What you will produce. Four analyses of your own corpus (a network, a diffusion simulation, a predictive model, and an embedding space), each run under a named epistemic purpose, and each with the challenge that purpose raises written down.

Materials for this chapter

Network analysis notebook

Bipartite construction, co-citation projection, k-core pruning, visualization, and a hypothesis test. Runs end to end on the sample data.

Sample network data

38,237 policy-to-scholarship edges as parquet, plus the projected co-citation network as GraphML, ready for Gephi.

Supervised learning, gently

Take this before §8.1.3 if you have never trained a model. Ships a runnable demo needing only scikit-learn.

Computational analysis tools

Network, simulation, prediction, and embedding libraries, maintained.

The capacities and purposes these exercises operationalize are developed in Chapter 7, which filters the studies database to computational analysis.

Prerequisites

The exercises reuse the coauthor network from Chapter 4 and the coded corpus from Chapter 6. If you have never trained a model, work through Supervised learning, gently before §8.1.3.

pip install networkx python-louvain gensim scikit-learn matplotlib mesa

§8.1.1 — Building the coauthor network

import itertools, networkx as nx

G = nx.Graph()
for authors in df["author_list"]:                 # list of author IDs per work
    G.add_nodes_from(authors)
    G.add_edges_from(itertools.combinations(sorted(set(authors)), 2))

print(G.number_of_nodes(), "authors;", G.number_of_edges(), "collaboration ties")
largest = G.subgraph(max(nx.connected_components(G), key=len))
print("largest component:", largest.number_of_nodes(),
      "| diameter:", nx.diameter(largest))

nx.shortest_path(G, a, b) gives the path the exercise asks you to interpret. On networks above a few thousand nodes, igraph is substantially faster than networkx because its core is compiled.

§8.1.2 — Diffusion simulation

The exercise turns on update order, so make it an explicit argument rather than an accident of how you wrote the loop:

import random

def diffuse(G, seed_node, p, steps=10, synchronous=True, rng=random.Random(42)):
    adopted = {seed_node}
    for _ in range(steps):
        newly = set()
        source = set(adopted)                    # snapshot: synchronous updating
        for node in G.nodes():
            if node in adopted:
                continue
            visible = source if synchronous else adopted   # asynchronous sees updates
            if any(nb in visible for nb in G.neighbors(node)) and rng.random() < p:
                newly.add(node)
        if not newly:
            break
        adopted |= newly
    return adopted

Run it both ways with the same seed and compare speed and final extent. The difference is Chapter 7’s temporal-dynamics point in miniature: update order is part of the model, not a software detail.

§8.1.3 — Non-linear prediction

Compare a linear baseline against a non-linear model on the same features and the same split. Report accuracy, precision, and recall on held-out data, and check the majority-class baseline first. See Supervised learning, gently for the full protocol and the leakage warning about fitting features before splitting.

§8.1.4 — Word embeddings

from gensim.models import Word2Vec

sentences = [t.lower().split() for t in df["text"]]
model = Word2Vec(sentences, vector_size=100, window=5, min_count=5, seed=42, workers=4)

model.wv.most_similar("equity", topn=10)
model.wv.most_similar(positive=["qualitative", "survey"], negative=["quantitative"])

Embeddings trained on a few thousand abstracts are noisy. If your corpus is small, load a pretrained model and treat the training run as a lesson about the algorithm rather than as a measurement instrument.

§8.2 — Epistemic purposes

Each exercise reuses the artifacts above under a different research goal: centrality and community detection for description, community membership as a predictor for explanation, held-out forecasting for prediction, and cross-period evaluation for integration. The substantive work is interpretive and the chapter supplies it; the code is the same libraries already listed.

import community as community_louvain
partition = community_louvain.best_partition(G, random_state=42)   # record the seed
nx.set_node_attributes(G, partition, "community")

Run community detection under several seeds before treating any partition as a finding. Chapter 10’s uncertainty exercise turns that instability into a figure.

§8.3 — AI validity audit

Compare the LLM labels from Chapter 6 against your dictionary or hand-coded labels on the same records, then read the disagreements. Chapter 7 (§7.4) supplies the framing: coding real data and generating synthetic data are different claims with different failure modes.

Where to go next