Health spending divergence: fast-growing vs stagnating EU health systems
Between 2000 and 2023, EU health spending trajectories diverged dramatically. Newer members like Romania, Poland, and Malta more than doubled their real spending, while Southern European countries barely grew — Italy +21%, Greece +26%.
This notebook examines health spending across all 27 EU member states using three WHO datasets:
EU_health_spend.csv — total health expenditure by financing type (2000–2023)
EU_spend_purpose.csv — spending by purpose/function (2016–2023)
EU_US_lifeExp.csv — life expectancy snapshots (2002, 2007, 2023)
Throughout, countries are grouped as fast growers (Malta, Ireland, Romania, Poland, Slovakia — red), slow growers (Italy, Greece, Portugal — blue), and other EU (grey) for context.
Setup and data loading
import pandas as pdimport matplotlib.pyplot as pltimport matplotlib.ticker as mtickerimport seaborn as snsimport numpy as npsns.set_theme(style='whitegrid', palette='colorblind')plt.rcParams['figure.figsize'] = (14, 6)plt.rcParams['figure.dpi'] =100# Load dataspend = pd.read_csv('data/EU_health_spend.csv')purpose = pd.read_csv('data/EU_spend_purpose.csv')life = pd.read_csv('data/EU_US_lifeExp.csv')# Harmonize Netherlands namingspend['country_name'] = spend['country_name'].replace('Netherlands (Kingdom of the)', 'Netherlands')purpose['country_name'] = purpose['country_name'].replace('Netherlands (Kingdom of the)', 'Netherlands')# Reference groupsFAST_GROWERS = ['Malta', 'Ireland', 'Romania', 'Poland', 'Slovakia']SLOW_GROWERS = ['Italy', 'Greece', 'Portugal']def group_label(country):if country in FAST_GROWERS:return'Fast growers'elif country in SLOW_GROWERS:return'Slow growers'return'Other EU'def group_color(country):if country in FAST_GROWERS:return'#e74c3c'elif country in SLOW_GROWERS:return'#2980b9'return'#555555'# Prepare CHE data (used throughout)che = spend[spend['expenditure_type'] =='Current Health Expenditure (CHE)'].copy()# Compute total growth 2000-2023 for sortinggrowth_00_23 = {}for c in che['country_name'].unique(): d = che[che['country_name'] == c] v0 = d[d['year'] ==2000]['value'].values v1 = d[d['year'] ==2023]['value'].valuesiflen(v0) andlen(v1): growth_00_23[c] = (v1[0] / v0[0] -1) *100ALL_COUNTRIES =sorted(growth_00_23, key=growth_00_23.get, reverse=True)# Small multiples layoutSM_NCOLS =5SM_NROWS =int(np.ceil(len(ALL_COUNTRIES) / SM_NCOLS))print(f'Spend: {len(spend)} rows, Purpose: {len(purpose)} rows, Life exp: {len(life)} rows')print(f'{len(ALL_COUNTRIES)} EU countries, sorted by total growth 2000-2023')print(f'\nFast growers: {FAST_GROWERS}')print(f'Slow growers: {SLOW_GROWERS}')
Spend: 2172 rows, Purpose: 1581 rows, Life exp: 67 rows
27 EU countries, sorted by total growth 2000-2023
Fast growers: ['Malta', 'Ireland', 'Romania', 'Poland', 'Slovakia']
Slow growers: ['Italy', 'Greece', 'Portugal']
1. The divergence: total health spending over time
How have EU countries’ spending trajectories diverged since 2000?
Show code
# Index to 2000 = 100 for all countriesche_idx = che[che['country_name'].isin(ALL_COUNTRIES)].copy()base_2000 = che_idx[che_idx['year'] ==2000].set_index('country_name')['value']che_idx = che_idx[che_idx['country_name'].isin(base_2000.index)]che_idx['indexed'] = che_idx.apply(lambda r: r['value'] / base_2000[r['country_name']] *100, axis=1)fig, axes = plt.subplots(SM_NROWS, SM_NCOLS, figsize=(20, SM_NROWS *3), sharex=True, sharey=True)for i, country inenumerate(ALL_COUNTRIES): ax = axes.flat[i] d = che_idx[che_idx['country_name'] == country] color = group_color(country) ax.plot(d['year'], d['indexed'], color=color, linewidth=2) ax.axhline(100, color='grey', linestyle='--', alpha=0.3, linewidth=0.5) ax.axvspan(2008, 2013, alpha=0.06, color='red') ax.axvline(2020, color='grey', linestyle=':', alpha=0.3) growth_pct = growth_00_23.get(country, 0) ax.set_title(f'{country} ({growth_pct:+.0f}%)', fontsize=9, fontweight='bold', color=color) ax.tick_params(labelsize=7)for j inrange(len(ALL_COUNTRIES), SM_NROWS * SM_NCOLS): axes.flat[j].set_visible(False)fig.suptitle('Total health expenditure growth, indexed to 2000 = 100 (constant 2023 USD)', fontsize=14, fontweight='bold')plt.tight_layout()plt.show()
Figure 1: Total health expenditure growth indexed to 2000 for all EU countries, sorted by total growth. Red = fast growers, blue = slow growers.
2. Did the eurozone crisis cause the stagnation?
Southern Europe was hit hard by austerity after 2008. Let’s see how spending changed in distinct periods.