Reproducing a published result on how much detail epidemic models need from mobile phone data, and then asking a question the original paper leaves open: does the level of detail change whether administrative borders look like sensible places to draw an intervention?
Built on the open data released with Pullano, Bansal, Rubrichi and Colizza (2026), Mobility data resolution needed to inform predictive models of spatial epidemic spread from mobile phone data, PLOS Computational Biology. Paper · Their data
Diseases spread because people move. So to predict where a disease goes next, you need a map of how people travel.
Phone networks have that map. Every phone quietly records roughly where it is, all day. In this dataset, Orange recorded the movement of 9.5 million people in Senegal, roughly 80% of the country, across 2013.
But you cannot feed raw phone records into an epidemic model. First you have to squash each person's messy daily movement into one simple number per pair of places: how strongly is village A connected to city B?
There is more than one way to do that squashing, and the choice is not obvious. Picture a single person's day.
| what it keeps | what one trip looks like | |
|---|---|---|
| HR high resolution | every phone ping, linked to the next | home → bus stop → town → town → city |
| MR medium resolution | only places where real time was spent | home → city |
| LR low resolution | only the single place where most time was spent | home → city |
Everyone's instinct is that HR must be best. It throws nothing away.
HR is the worst of the three.
Here is the reason, and it is the whole idea.
A person travels from a village to the capital. That is one meaningful connection: village to capital. But their phone pinged five times along the road. So HR does not store one long link. It stores five short hops. The village to capital connection gets chopped into pieces and effectively disappears.
MR does not have this problem. It ignores the journey and simply notes: this person lives in the village and spends hours in the capital. One link, recorded.
So the most detailed method is the one that systematically loses long distance connections. And long distance connections are exactly what carry a pathogen across a country. HR sees a country full of small local movement and almost no big jumps.
The practical conclusion is a good one for privacy: you do not need people's full movement traces. Knowing roughly where people spend their time is enough, and that can be shared in a much more aggregated form.
The model released with the paper is C++ written for a computing cluster. It expects preprocessed input files under hardcoded absolute paths that are not in the public repository, and it links against GSL, so it does not run as published. The coupling matrices and the census file are published, so the model can be rebuilt from them.
src/metapop.py is an independent reimplementation in Python, written from the released C++ source, keeping the transmission structure identical.
The model. Let sigma[i,j] be the probability that a resident of municipality i is present in municipality j. Rows sum to one, self loops included.
N_eff[k] = Σ_i sigma[i,k] · N[i] people effectively present at k
I_eff[k] = Σ_i sigma[i,k] · I[i] infectious effectively present at k
p[i] = β · Σ_k sigma[i,k] · I_eff[k] / N_eff[k]
p[i] is the daily chance a susceptible resident of i is exposed. It is one line, but it contains the three routes the original writes out separately: infected at home by a neighbour, infected at home by a visitor from elsewhere, or infected while travelling and carrying it home.
Transitions are then S→E ~ Bin(S, p), E→I ~ Bin(E, 0.67), I→R ~ Bin(I, 0.33), with β = R₀ · 0.33. Daily timestep, coupling matrix swapped each calendar month. 394 municipalities, 11.5 million residents.
| quantity | published | this reimplementation |
|---|---|---|
| median off diagonal coupling, HR | 8.4 × 10⁻⁶ | 7.3 × 10⁻⁶ |
| median off diagonal coupling, MR | 1.0 × 10⁻⁴ | 9.5 × 10⁻⁵ |
| median off diagonal coupling, LR | 1.5 × 10⁻⁴ | 1.5 × 10⁻⁴ |
| MR links absent from HR | 37% | 38% |
| LR links absent from HR | 27% | 32% |
Median arrival time across all 394 municipalities, in days, 50 stochastic runs per condition, seeded in Dakar:
| R₀ | HR | MR | LR |
|---|---|---|---|
| 1.5 | 72.3 | 38.0 | 40.2 |
| 3.0 | 28.0 | 14.6 | 15.2 |
HR predicts the epidemic covering the country roughly 1.8× slower than either coarser representation. MR and LR sit almost on top of each other. That is the paper's central claim, reproduced independently. The figure at the top of this README shows the same thing as invasion curves.
Recorded here as an open question rather than a correction, since it does not affect any downstream result.
For Figure 2b the paper reports "outgoing probabilities are higher in HR compared with MR and LR (0.86 in HR, 0.62 in MR, 0.69 in LR)".
In the released matrices, averaged over all twelve months, the diagonal entries are HR 0.853, MR 0.648, LR 0.712. Those are the quoted values. Read that way, 0.86 / 0.62 / 0.69 is the probability of staying, and the outgoing probability for HR would be 0.147, the lowest of the three rather than the highest.
The lower figure is also what the paper's own mechanism predicts: the next sentence explains that HR generates additional self loops which "substantially reduce the probability of moving". Every result downstream is consistent with HR being the most home bound representation. It reads like a labelling or wording slip in that one sentence. If I have misread the figure, I would be glad to be corrected.
The paper settles how detailed the movement data has to be. It holds the spatial unit fixed, and that unit is administrative.
That leaves the adjacent question untouched. Public health measures are almost always applied along official boundaries: this department is under restriction, that one is not. Do those boundaries have anything to do with how people actually move?
The Senegal data can answer that directly. The census location codes encode the administrative hierarchy, giving 14 regions and 47 departments over the same 394 municipalities.
src/mobility_vs_admin.py builds a mobility network weighted by people moved rather than probability, runs Louvain community detection to find groups of municipalities more tightly bound to each other than to the rest of the country, and compares the result against both administrative layers.
Share of all movement between municipalities that crosses the boundary in question, September, MR coupling:
| boundary | movement crossing it |
|---|---|
| region, 14 units | 43.8% |
| department, 47 units | 64.2% |
Read plainly: restrict a single department, and roughly two thirds of the ordinary movement you were trying to contain crosses your line anyway.
The data driven partition does not match the official one either. Louvain finds 8 mobility clusters where the administration has 14 regions, with an adjusted Rand index of 0.40 and normalised mutual information of 0.65 between them. Related, but clearly not the same map.
Run the same measurement on the HR network and only 15.4% of movement appears to cross a region boundary, against 43.8% under MR.
So the low quality representation makes the country look neatly contained by its own administrative map. That apparent containment is an artifact of the same trip fragmentation that makes HR simulate invasion 1.8× too slowly: the long trips it deletes are precisely the border crossing ones.
The choice of mobility representation silently determines whether administrative boundaries look adequate. An evaluation of border based interventions built on displacement style data would conclude those borders work considerably better than they do.
That link is the contribution here. The reproduction in Part 1 is the paper's result. This is not.
- Everything here uses the published aggregated matrices. No raw trajectories were touched, so the aggregation step itself, where the actual methodological choice lives, is taken as given.
- One country, one year, 2013. Whether mobility clusters stay stable enough over time to scope a real intervention is untested and is the obvious next question.
- The transmission model is reproduced; the invasion tree and betweenness analyses in the original are not.
- Louvain is stochastic and resolution dependent. The seed is fixed for reproducibility, but the number of clusters should be read as approximate.
git clone https://github.com/aaliusama/mobility-resolution-and-borders.git
cd mobility-resolution-and-borders
pip install -r requirements.txt
./run_all.sh # fetches the upstream data, regenerates everything in results/run_all.sh 200 runs 200 stochastic simulations per condition instead of the default 50.
src/metapop.py SEIR metapopulation model, reimplemented from the released C++
src/run_comparison.py HR vs MR vs LR invasion comparison across R0 and seed locations
src/mobility_vs_admin.py Louvain clusters vs regions and departments, boundary leakage
src/make_figure.py invasion curves
results/ generated tables and figure
docs/METHODS.md fuller notes on the model and the checks
The mobility coupling matrices and the 2013 census file are not redistributed here. run_all.sh clones them from the authors' repository. All credit for the dataset, the modelling framework and the resolution finding belongs to the original authors:
Pullano, G., Bansal, S., Rubrichi, S., & Colizza, V. (2026). Mobility data resolution needed to inform predictive models of spatial epidemic spread from mobile phone data. PLOS Computational Biology, 22(7), e1014427. https://doi.org/10.1371/journal.pcbi.1014427
Code in this repository is MIT licensed. See LICENSE.
Ali Usama · github.com/aaliusama
Claude Cowork was used as a productivity tool during this analysis.
