SPB Git

spb/wp29_uqo

Public

# F6-dev-01 — Income and life expectancy across countries: a bounded mini-project

# Scientific question

Does the cross-country relationship between real income per capita and life expectancy (the "Preston curve") hold in the most recent year with usable World Bank data, and how strong is it? The estimand is the slope β of the linear projection LE_i = α + β·ln(GDPpc_i) + ε_i across countries/economies (one equally weighted observation per country) in the analysis year, where LE is life expectancy at birth (years) and GDPpc is GDP per capita in PPP constant 2021 international dollars, with heteroskedasticity-robust uncertainty. The task is a complete, bounded chain: question → data audit → baseline → justified method → results → uncertainty → failure discussion → one figure and one table → short report. "Effect" is used here in the descriptive, associational sense: no causal claim is requested.

# Inputs

  • data/wb_indicators.csv — observed data, World Bank World Development Indicators (retrieved 2026-10-30, CC BY 4.0; full provenance, URLs and SHA-256 in data/README.md). One row per entity-year, 2015–2023. Columns: iso3, name, year, gdp_pc_ppp (GDP per capita, PPP, constant 2021 international $; empty if not reported), life_expectancy (years; empty if not reported). The file is the API download for all World Bank entities, so it contains countries/economies as well as regional and income-group aggregates.
  • data/wb_entities.csv — World Bank entity metadata: iso3, name, region (the value Aggregates marks groupings that are not countries/economies), income_level, lending_type.
  • data/README.md — provenance.

# Information-availability rules

  • The analysis population is countries/economies only: exclude every entity whose region is Aggregates in wb_entities.csv.
  • The analysis year is the most recent year (2015–2023) in which both indicators are observed for at least 150 countries/economies. Report it as analysis_year.
  • In the analysis year, countries/economies with either indicator missing are excluded from the estimate and counted in n_excluded_missing. No imputation.
  • Use the natural logarithm of GDP per capita. Use only the files listed above.

# Required outputs

  • out/results.json with the keys:
key type unit meaning
analysis_year integer year year selected by the rule above
n_excluded_missing integer countries countries/economies present in wb_indicators.csv for the analysis year but dropped for a missing indicator
baseline_metric number years RMSE of the mean-only prediction of life expectancy, sqrt(mean((LE − mean LE)²)) over the analysed countries (the no-information baseline)
model_metric number years RMSE of the OLS residuals, sqrt(mean(e²))
pearson_r number — Pearson correlation between ln(GDPpc) and LE
r_squared number — R² of the OLS regression
effect_estimate number years per log-point OLS slope β
intercept number years OLS intercept α
effect_se number years per log-point heteroskedasticity-robust standard error of β (HC0–HC3; state which in the report)
effect_ci_low, effect_ci_high number years per log-point 95% confidence interval for β based on effect_se
conclusion string — one of the codes below
task_id string copied from this file
feasibility string complete / partial / infeasible
feasibility_reason string or null why, if not complete
data_issues array of {"issue","handling"} every data problem detected and how it was handled (empty list allowed)
n_input_rows object {file: integer} rows read per input file (file name as key, header row excluded)
n_analysed integer or null observations actually used in the main estimate
random_seed integer or null seed used, if any

The conclusion code must be one of: positive_effect (the 95% interval for the effect estimand lies above zero), negative_effect (lies below zero), no_detectable_effect (the interval / test does not reject zero at the 5% level), premise_invalid (the data provided do not allow the stated estimand to be computed — in that case set feasibility to infeasible, explain in feasibility_reason, and set every inestimable key to null; never substitute an invented or proxy estimate).

  • out/figure1.png — scatter of life expectancy against ln(GDP per capita) for the analysed countries with the fitted OLS line, produced by out/analysis.py with matplotlib.
  • out/table1.csv — one row per World Bank income level present among the analysed countries, with columns income_level, n_countries, mean_log_gdp_pc, mean_life_expectancy (header row + at least two data rows), produced by out/analysis.py.
  • out/report.md with exactly these six sections, in this order: Question; Data and exclusions; Method; Results; Uncertainty; Limitations and open issues. The last section must contain a genuine failure discussion: what would invalidate the result, what was not checked, and what the main threats are.
  • out/analysis.py — replication entry point: ~/wp29/venv/bin/python out/analysis.py, run from the workspace root, must regenerate out/results.json, out/figure1.png and out/table1.csv from data/ only, deterministically (fix any seed; use the matplotlib Agg backend).
  • out/claims.json — list of the central claims of the report: [{"id": "C1", "text": "...", "results_keys": ["..."], "status": "supported"|"unsupported"|"not_evaluated", "caveat": "..."}]. Every claim must reference existing keys of out/results.json; a claim must only be marked supported if the reported numbers actually support it.

# Constraints

  • No network access. Python: ~/wp29/venv/bin/python (numpy, pandas, scipy, statsmodels, matplotlib available). Do not modify data/.
  • Write all deliverables under out/. This task is designed to be completed in well under 20 minutes of work; prefer a short, correct chain over an elaborate one.
Files · main
Menu

Theme