What a Spillover Flag Does Not Buy You

research
Modeling conflict severity in SCAD v3.3 across Africa and Latin America, where the spillover term I built the project around turned out not to be significant.
Published

August 16, 2026

SMBA graduation day. The capstone this document describes was the last major deliverable.

SMBA graduation day. The capstone this document describes was the last major deliverable.

This was the capstone research project for my SMBA. The brief: model conflict severity across Africa and Latin America using the Social Conflict Analysis Database, with a novel spillover operationalization as the central contribution.

The spillover flag was the point of the project, and in the severity model it did nothing. Coefficient 0.084 on the log link, not significant, in a Negative Binomial GLM fit on 7,361 training events. Three quarters of events in both regions are flagged as spillover under the canonical threshold, and knowing that tells you almost nothing about how many people die.

That is the finding. The rest is how I got there and what I think the flag is actually good for.

Data

Social Conflict Analysis Database v3.3, Africa and Latin America, 1990 through 2017. Raw: 17,644 Africa rows, 5,602 Latin America rows. After cleaning, 23,159 events. After complete-case restriction on escalation, duration, participants, and coordinates, 9,900 rows in the classifier universe and 9,814 with an observed death count.

That is 57.2 percent attrition, and it is not a rounding issue. SCAD codes missing deaths with sentinels: -99 unknown, -88 probably small, -77 probably large. All three become NA for the count model. The -77 rows are not random missingness, though. The codebook treats them as a signal that the event was large, so I assign high_sev = 1 to those rows before the NA conversion. Eighty-six of them survive the other completeness filters and enter the classifier training set with a known label and an unknown count. High-severity prevalence is 9.7 percent.

One structural feature of SCAD v3.0 and later matters more than it looks: each row is an event-location pair. The same eventid appears once per location for multi-location events. Death totals computed naively across rows overcount. The ratio of unique eventids to rows is 0.901, which cleared the 0.90 threshold I set in advance for using standard errors unclustered. I would rather state the rule before seeing the number than justify the choice afterward.

Spillover definition

An event is flagged as spillover if it occurs within 250 km and within 90 days of a prior event in the same region. Haversine distance on latitude and longitude. The partition is regional, not by country, because cross-border contagion is the phenomenon of interest and a country partition defines it away.

Buhaug and Gleditsch (2008) use 500 km. I use half that, which makes the operationalization more conservative than the literature it comes from.

I also ran a sensitivity grid across distance and time combinations. The best cell by pseudo-R² was 100 km / 30 days, at 0.002. I kept 250/90 anyway. Choosing a measurement threshold because it maximizes downstream fit is leakage wearing a lab coat, and the flatness of the grid is itself the argument that the choice does not matter much. The grid is reported; the winning cell is not adopted.

Flag rates: Africa 75.0 percent, Latin America 76.5 percent.

The centroid artifact

Events coded locnum = 7 (nationwide) or locnum = -99 (unknown) have no real coordinates. They get placed at country centroids. My expectation was that this manufactures artificial spatial clustering and inflates the spillover rate, so I built a centroid_flag and recomputed with those events excluded, expecting the rate to fall.

It rose. Africa 76.2 percent, Latin America 78.1 percent, against 75.0 and 76.5 with centroids included. Centroid events sit in geographic interiors, away from the dense coastal and border conflict clusters where real events pile up. Removing them removes a set of events that were unusually unlikely to be near anything, and the remaining population is denser.

Roughly 11.0 percent of Africa events and 10.2 percent of Latin America events are centroid-placed. The artifact is real. It just runs the opposite direction from the one I wrote into the plan.

Severity model

Negative Binomial GLM on ndeath. Poisson first, as a check: Pearson dispersion 40.4, which is not a close call and settles the distributional question.

m_nb_ew <- MASS::glm.nb(
  ndeath ~ factor(etype) + log_duration + log_npart +
           cgovtarget + rgovtarget + repress + region +
           styr_scaled + cy_events_log + cy_events_lag1 + spill_hav,
  data = ds_train_cnt
)

McFadden pseudo-R² 0.123, AIC 22,127.9, N = 7,361. Coefficients on the log link, so exponentiate for the multiplier on expected deaths:

Predictor Coefficient
Log duration 0.742***
Log participants 2.475***
Repression 1.595***
Central government target -0.509***
Regional government target -0.170
Latin America -0.991***
Log country-year events 0.102*
Log country-year events, lag 1 0.182***
Spillover flag 0.084

Two things worth sitting with. The lagged country-year event count outpredicts the contemporaneous one, 0.182 against 0.102. Cumulative buildup is associated with severity more strongly than current-period intensity is. And events targeting the central government are associated with fewer deaths, not more, which is the opposite of the intuition I started with and probably reflects that capital-city protest is heavily represented and heavily policed rather than lethally suppressed.

escalation is absent from this specification and that is deliberate. SCAD assigns escalation levels 4 through 10 post hoc, after deaths are tallied. It is an excellent predictor of deaths for the same reason a thermometer is an excellent predictor of a fever. Every escalation-inclusive model in the project was cut for this reason, including the versions where I kept only the continuous measure and dropped the binary flag. Removing one and keeping the other does not fix an endogeneity problem, it just makes it harder to see.

ZINB, disclosed rather than dismissed

A zero-inflated Negative Binomial fits better. AIC approximately 20,726.6 against 22,127.9, a delta of 1,401.3 in ZINB’s favor. That is not marginal and I am not going to call it a robustness check that the NB passed.

I kept the NB as the primary model on interpretability grounds for a managerial audience: a single log-link coefficient table that reads as multipliers on expected deaths, against a two-equation structure requiring a separate story about which zeros are structural. The tradeoff is stated in the report as a limitation, not buried in an appendix.

The Vuong statistic is not reported. The parse failed, the test is contested for non-nested comparisons of this kind anyway, and the AIC delta is conclusive on its own.

Classifier

Random Forest on the binary high-severity outcome, early-warning specification, meaning no escalation and no esc_high among the predictors. Class weight of 5 on the minority class.

AUC 0.937. Recall 0.629. Accuracy 0.930. Brier 0.055, Brier skill score 0.372.

The recall is a miss. I set the analytical bound at 0.75 before running the model and the model came in at 0.629, so it is reported as a failure against the bound. AUC says the model ranks cases well. Recall says that at the operating threshold it lets roughly 37 percent of high-severity events through. For an early-warning system that is the number that matters, and improving it means moving the threshold and accepting more false positives, which is a resource decision rather than a modeling one.

Top predictors by Gini: event type, log country-year events current and lagged, year, log participants, log duration, then the actor and target grouping factors.

What the flag is for

The counterfactual, setting spill_hav = 0 across all rows in the NB, returns a 6.9 percent reduction in predicted deaths. I report it as a model-based upper bound and nothing else. It is the arithmetic consequence of a non-significant coefficient, and reading it as a causal estimate would be reading noise as policy.

So the spillover flag is not a severity amplifier and should not be sold as one. What it is: a concentration statement. Three quarters of events occur within 250 km and 90 days of a prior event. That is a claim about where and when events cluster, which is exactly the input a pre-positioning decision needs, and it is a different claim from “spillover events kill more people.” The first is supported. The second is not.

I built the project expecting the second and got the first. The honest version of the writeup says so.

Open

The 250/90 threshold is defensible on domain grounds but the grid is flat, which means the definition is doing less work than the framing implies. The 57.2 percent attrition could be non-random if missing coordinates correlate with event type or region, and I have not tested that directly. And the per-event mortality contrast (roughly 13 deaths per event in Africa against roughly 2 in Latin America) is computed on unique eventids, while the regional summary table is computed on event-location rows and gives 6.96 against 1.06. Same direction, different base. Both are correct and they read as contradictory unless the base is stated every time, which is the kind of thing that is invisible until someone puts the two tables side by side.

Data: SCAD v3.3, public. Pipeline in R 4.3.3, MASS, randomForest, pscl, geosphere.

Code

The pipeline, in order: cleaning, descriptive, predictive, spillover, prescriptive, economic extension. SCAD itself isn’t redistributed here — pull it directly from the SCAD project rather than from a derivative copy.