ErasmusGravity
ErasmusGravity · unilife.ellep.it

What pulls a student across a border?

Research question: what explains the size of Erasmus+ Higher Education flows from one country to another? We frame destination choice as a gravity-style model where flows respond to the salary gap, perceived quality of life, institution quality, and language affinity between origin and destination.

KA1 study mobility · cross-border country pairs

The modelA gravity model of student flows

We model each origin–destination flow as a gravity-style regression. This is the project's step-3 design: the specification below describes how the collected text and spatial data would be used to answer the research question. It is documented, not estimated.

log(1 + flowij) = β₁·gdp_gapij + β₂·quality_of_lifej + β₃·institution_qualityj
    + controls(distance, language_affinity)
    + origin FE + destination FE + τt (year FE) + postt·covid_hitj,s + εij
robustness only (exploratory, multicollinear with β1): + gdp_gap, price_level_gap

Tap a term to jump to its evidence section. The β cards lead to the explanatory variables; the controls link lands on the gravity controls block.

The two bilateral frictions distance and language_affinity are the headline gravity controls (low VIF, identifying). gdp_gap and price_level_gap are not in the main spec — they proxy the same rich-vs-poor dimension as salary_gap (VIFs ≈ 5–7) and are kept as an exploratory robustness block. Origin and destination FE absorb broad country-level differences; the estimate is descriptive, not causal.

The βsExplanatory Variables

Each term in the model and its data source. built = data already in the processed pipeline; planned = part of the described design (text layer / rankings / language groupings).

β₁· built

GDP-per-capita gap

Role: Broad destination-prosperity control
Source: World Bank GDP per capita (gdp_gap_usd_wb)
Sign: + (richer destinations associated with more flow, broad control)
β₂· built

Quality of life

Role: Explanatory – perceived liveability
Source: Reddit r/Erasmus, sentiment + themes via OpenRouter (DeepSeek) + Pydantic (text layer)
Sign: + (better perceived life attracts flows)
β₃· built

Institution quality

Role: Explanatory – academic pull
Source: QS World University Rankings 2023, geocoded + snapped to destination city (institution_quality.csv)
Sign: + (stronger universities attract flows)
control· built

Language affinity

Role: Control – origin–destination language affinity (gravity friction)
Source: Shared language-family dummy (geo.py LANGUAGE_FAMILY)
Sign: + for shared/affine language family
control· built

Distance

Role: Control – gravity friction
Source: Origin-country centroid → destination-city great-circle km (geo.py)
Sign: − (farther destinations deter flows)
robustness· built

Salary gap

Role: Robustness only – salary heterogeneity (overlaps GDP gap)
Source: Eurostat net earnings (earnings_gap, sector_earnings_2018.csv)
Sign: ambiguous (VIF ~7 with GDP gap; not a headline term)
robustness· built

Price-level gap

Role: Robustness only – cost of living (overlaps GDP gap)
Source: Eurostat price levels (price_level_gap)
Sign: ambiguous (VIF ~6.5 with GDP gap; not a headline term)

ResultsModel Results

Every coefficient (β) — headline PPML gravity model

All estimated terms from the cross-sectional PPML model (Poisson on flow level, city-clustered SEs), plus the planned terms not yet built. Significant (p<0.05) in accent. Natural-unit effect is the % change in flow for a tangible unit change — +€1,000 salary gap, +1 Erasmusu rating point, +10 QS score points, doubling distance.

Quality-of-life coefficient across specifications

β₂ across all specs. Outcome is log(1+flow) (OLS/WLS) or flow level (PPML); p-values cluster-robust. Headline: the city-level two-stage (panel destination attractiveness explained by Erasmusu rating).

The same gravity model run on the year panel and through a 2020 shock lives in the Time & Shocks act below.

The dependent variable

What we are explaining — the flows themselves

flowij

Filter the flows

Outgoing country Default: Italy. Drives the summary cards, trend chart, scatter and map.
Narrow further (optional)

Picking an 🛫 outgoing university narrows the map and table to flows leaving that institution. Picking an 🛬 incoming country or 🛬 incoming university keeps only flows arriving there. Filters AND-combine: the more you set, the smaller the view.

flowijSelected Country Overview Showing

Use the sending-country selector in the top bar. Main flow definition: Higher Education learners, study mobility activity, age 18+, cross-border flows only.

flowijUniversity Flow Map Showing

smaller flow larger flow One point per university endpoint, sized by students. Zoom out to aggregate nearby universities into clusters; click a cluster to zoom in and pick a university. Universities sit at their city coordinate; cities without a coordinate match fall back to their country centroid.

flowijTop Destinations Showing

flowijDestination table Showing

flowijFlow Heatmap

Rows and columns use the same country order: countries are sorted by total Erasmus flow volume among the displayed top countries.

Controls & gravity frictions

What we hold constant — plus an exploratory economics block

controls

β₁ vizGDP Gap and Flow Share Showing

GDP gap = receiving-country GDP per capita minus sending-country GDP per capita (broad prosperity control, β1). Flow share = flow to that destination divided by all outgoing flows from the selected sending country.

robustnessFlow-Weighted Destination Economics — salary & price-level (robustness)

Reported as robustness, not headline controls. salary_gap and price_level_gap proxy the same rich-vs-poor-destination dimension as the headline gdp_gap1): VIFs ≈ 5–7 in the full-controls PPML, so the three monetary gaps split one signal three ways. The full-economic-controls spec is kept here as an exploratory check because of this multicollinearity, not because the economics are uninteresting. See reports/gravity_model.md §4.

Click column headers to sort. Destination metrics are weighted by each sending country's flow counts.

The explanatory variables

What pulls students toward a destination

β₁ · β₂ · β₃

β₁GDP-per-capita gap — broad prosperity control

Destination minus origin GDP per capita (World Bank, current USD). Read as a broad prosperity control, not as a causal economic-pull effect. Salary gap and price-level gap are demoted to robustness because they overlap with GDP and produce an unstable monetary block (VIF ~6.5–7 in the full controls spec).

📚 Source
World Bank GDP per capita (current USD)
gdp_gap_usd_wb · pair-level destination minus origin, joined onto the KA1 2022 panel.
⚙️ Estimation
PPML on bilateral flows, city-clustered SE
Cross-section Poisson with sending-country FE on the 2022 KA1 panel; gdp_gap enters as the only monetary term.
🎯 Effect
loading…
🔍 Evidence (robustness)
NACE-sector earnings explorer
Pick a country & unit below to compare monthly earnings by sector — the salary heterogeneity behind the demoted salary-gap robustness term. See full controls breakdown under Controls.

Mean monthly gross earnings by NACE economic sector, Structure of Earnings Survey 2018. This is a salary-by-sector reference, not salary by field of study (Eurostat does not publish earnings by field of study). Coverage is limited to the 17 countries that report this dataset.

β₂Quality of life — perceived liveability

A text layer over r/Erasmus and a numeric layer from Erasmusu city ratings. Tests whether students are pulled toward places that read as friendlier, cheaper, livelier in student talk.

📚 Source
Reddit r/Erasmus + Erasmusu city ratings
Destinations extracted via OpenRouter (DeepSeek) + Pydantic · sentiment, themes, city/country. Weighted-net sentiment uses confidence × log(1+upvotes) × EWMA age-decay (1-year half-life), so stale opinions fade as fresh ones arrive on re-scrape.
⚙️ Estimation
City-level two-stage
Stage 1: panel destination attractiveness from PPML year FE. Stage 2: attractiveness explained by Erasmusu rating, cluster-robust SE.
🎯 Effect
loading…
🔍 Evidence
Per-country sentiment table
Net sentiment = (pos − neg) / mentions · small per-country counts, treat as qualitative signal. See table below.

Destination mentions extracted from r/Erasmus posts and comments. Score-weighted net also weights by extraction confidence and log Reddit score. Click headers to sort.

β₃Institution quality — academic pull

Each destination university enters as a ranking score. Tests whether stronger universities pull more inflow once salary gap, distance, and language affinity are held constant.

📚 Source
QS World University Rankings 2023
QS overall score (0–100 composite of research, teaching, employability, internationalisation). Each Erasmus city gets its best-ranked university's score. European institutions geocoded via Nominatim and snapped to the nearest Erasmus city within 35 km · institution_quality.csv.
⚙️ Estimation
PPML, ranking score on destination city
Same gravity spec as β₁ with the destination's best-ranked university score added as a city-level regressor.
🎯 Effect
loading…
🔍 Evidence
Crowd cross-check: StudyPortals
User ratings of universities, scraped from Wayback. Independent crowd-vs-expert signal · user_institution_quality.csv.

Headline finding: adding institution quality attenuates β₂ by roughly a quarter — perceived liveability and academic pull share signal. See Model Results for the full coefficient table.

Time & shocks

The model run through every year — and the 2020 break

Σt

panelPanel gravity — year fixed effects (2014–2023)

We refit the gravity PPML on the panel of country-pair flows by year (2014–2023), with origin×destination fixed effects absorbing all time-invariant bilateral pull (distance, language, history, geography) and year fixed effects picking up the common time path. The plotted series is each year's FE relative to 2014 — read it as the log-change in expected flow for any given pair, holding gravity constants fixed.

A flat line would say "Erasmus volume is stable once you control for gravity". Instead we see a steady positive drift through 2019 (program scale-up), the sharp 2020 collapse when borders closed, a partial 2021 rebound, and a return above the 2019 baseline by 2023 — the gravity model says the recovery is real, not a composition artifact of which countries reopened first.

How to read: dot = year FE coefficient · dashed line = 2014 baseline (0) · coral 2020 marker = COVID shock year.

Time-varying regressors — the same gravity model, run year-by-year

When we let a regressor itself vary by year (instead of absorbing time into a single FE), within-destination movement over time identifies it. Three time-varying panels are estimated. Two of the three say something; one says nothing — that null is itself worth reading.

What is a "life-satisfaction point"? The OWID series uses the Cantril ladder from the Gallup World Poll / World Happiness Report: respondents rate their current life on a 0–10 scale ("worst possible life" to "best possible life"). The country score is the mean response. A "+1 life-satisfaction point" means moving the destination's annual mean one full rung up the ladder — e.g. roughly the Spain↔Switzerland gap in 2022. Source: data/processed/owid_country_year.csv.

β₂ time-varying QoL
loading…
OWID life satisfaction (Cantril ladder), 99 countries × 10 years. Origin + destination + year FE, dest-clustered SE.
edu spending %GDP
loading…
OWID government education spending. Same FE structure as life satisfaction. Insignificant — a useful null.
β₃ time-varying QS
loading…
QS World Rankings 2014/2017/2018/2023 (Wayback editions), snapped to Erasmus cities. Dest-city + origin + year FE.

Read: only life satisfaction identifies cleanly as time-varying — +25.4% per life-satisfaction point, p=0.035. The other two are null. The QS null reflects QS-score stickiness (within-city year-to-year variance is tiny); the education-spending null suggests within-country temporal drift in public-education investment doesn't move Erasmus flows.

shockCOVID-2020 sector DiD on field-level flows

We move from the smooth year-FE path to a real, date-pinned shock. Each ISCED-F broad field of study is mapped to one NACE sector, then we ask: did flows into (destination, field) cells whose mapped sector was hit harder in 2020 fall by more, relative to 2019? We run it twice — once with wage-based hit (LCI), once with employment-based hit (LFS) — because the LCI 2020 series is contaminated by wage-subsidy schemes.

📚 Source
Two hit measures, same panel
LCI covid_sector_hit.csv — sector wage growth deviation, 2015–2019 baseline. LFS covid_employment_hit.csv — sector employment growth deviation, same baseline. Field → NACE map in src/erasmusgravity/fields.py.
⚙️ Estimation
PPML, dest×field + sending + year FE, cell-clustered SE
268–328 (destination, field) cells · 39 origins · 2014–2023 · Turkey dropped (hyperinflation). Same FE structure across both measures so coefficients are directly comparable.
🎯 Effect
loading…
loading employment hit…
🔍 Evidence
Headline finding: shock identified at 2020-2021, but channel is uniform
LCI: pre-trends pass (2015-2018 all p>0.07), sharp 2020 break (p=0.004), persistence 2021 (p=0.012), fade by 2022 — the event-study shape COVID would produce, but the sign is wrong because LCI is contaminated by wage subsidies (NL NOW, Kurzarbeit). Employment replication: sign flips back to positive (consistent prior) but the signal collapses — no significant year. Read together: COVID's 2020 hit on Erasmus was lockdown-wide, not sector-selective at the field-of-study resolution we observe.

How to read: two series of year×hit interactions (2019 as reference). Coral = LCI wage-based hit. Teal = LFS employment-based hit. Filled dots = p<0.05. Dashed horizontal line at zero. Dashed vertical line marks 2019 reference. LCI on a different y-scale from LFS — coefficients in the Effect card read as "% flow change per 1 pp harder hit sector".

NotesData Sources and Measurement Notes