# Access to Opportunity in the Sciences — Replication Package

[How to cite](CITATION.cff) · [License](LICENSE.md)

Code and data to reproduce the results in:

> Novosad, Paul, Sam Asher, Catriona Farquharson, and Eni Iljazi (2026).
> "Access to Opportunity in the Sciences: Evidence from the Nobel Laureates."
> Working paper.

The paper studies the socioeconomic origins of Nobel laureates in the sciences
(1901–2023). Each laureate's background is measured by the percentile rank of
their father's occupation, by income and by education, within the laureate's
country and census decade, and against the global income distribution.

## Quick start

```sh
conda env create -f code/environment.yml
conda activate nobel-prizes
python code/run_all.py --check
```

`--check` re-runs every analysis (about 15 seconds) and compares the results
with the copies shipped in this package. A successful run ends with:

    All 16 script(s) reproduced the shipped results.

Before comparing, `--check` confirms the shipped outputs are untouched (their
checksums are in `code/shipped_outputs.sha256`); a plain `run_all.py` run
overwrites them, after which `--check` reports "not verified" until you
re-extract the package. You can rename the folder and run from any directory.

## What's inside

```
data/            input datasets (CSV) and codebook.csv — see data/README.md
code/            one analysis script per result — see code/README.md
  run_all.py     run everything (--check to verify, --only NAME for a subset)
  manifest.py    the script list and the exhibits each reproduces
  shipped_outputs.sha256  checksums of the shipped results, used by --check
  examples/      a worked example to copy for your own analysis
CITATION.cff     how to cite the paper
LICENSE.md       MIT (code), CC BY 4.0 (data)
AGENTS.md        instructions for AI coding assistants working in this package
```

## Where each result comes from

| PDF exhibit | Script | Output |
|---|---|---|
| Figure 1 | `code/rank_histograms/rank_histograms.py` | `rank_histograms.json` |
| Figure 2, Figure A2 | `code/main_binscatter_ranks/main_binscatter_ranks.py` | `binscatter_ranks.json` |
| Figure 3, Table 3, Figure A4 | `code/parent_field_match/parent_field_perm_test.py` | `parent_field_perm_test.json` |
| Table 1, Table A7 | `code/main_spec/main_spec.py` | `main_spec.json` |
| Table 2 | `code/heterogeneity_spec/heterogeneity_spec.py` | `heterogeneity_spec.json` |
| Figure A1 | `code/most_common_occupations/most_common_occupations.py` | `most_common_occupations.json` |
| Figure A3 | `code/other_rank_functions/other_rank_functions.py` | `other_rank_functions.json` |
| Figure A5 | `code/parent_field_match/parent_field_match_graphs.py` | `parent_field_match_shares.json` |
| Table A1 | `code/father_occ_by_category/father_occ_by_category.py` | `father_occ_by_category.json` |
| Tables A2, A3 | `code/occ_shares/occ_shares.py` | `occ_shares_10group.json`, `occ_shares_25group.json` |
| Table A4 | `code/occ_representation_change/occ_representation_change.py` | `occ_representation_change.json` |
| Tables A5, A6 | `code/main_robust/main_robust.py` | `main_robust.json` |
| Table A8 | `code/gender_spec_robust/gender_spec_robust.py` | `gender_spec_robust.json` |
| Table A10 | `code/regional_analysis/regional_analysis.py` | `regional_analysis.json` |
| Table A12 | `code/hetero_trends/hetero_trends.py` | `hetero_trends.json` |
| Table A13 | — (this table *is* the data file) | `data/occ1950_sci_field_classification.csv` |

Outputs are JSON files in each script's own `output/` folder.

## Supplementary panel numbering

Supplementary panels use one sequence, A1–A19, by first appearance in reading
order: Introduction, Data and Methods, then Results; body text (including
expandable details) precedes each section's Notes list. Repeated references keep
the same number. These panel ids are independent of the PDF's separate appendix
figure and table numbering. The preceding exhibit table and the scripts' original
`paper_table` metadata retain PDF labels for comparison.

| Panel | Title | Script or source |
|---|---|---|
| A1 | Galton, English Men of Science (1874) | Galton (1874), English Men of Science |
| A2 | Robustness to sample restrictions | `code/main_robust/` (PDF Table A5) |
| A3 | The gender gap, under four robustness samples | `code/gender_spec_robust/` (PDF Table A8) |
| A4 | Getting an income or education rank from a father occupation | Worked rank examples from `data/nobelists_analysis.csv` |
| A5 | Most common father occupations | `code/most_common_occupations/` (PDF Figure A1) |
| A6 | Secular trend in father rank, by gender | `code/gender_analysis/` |
| A7 | Regional differences in elite backgrounds | `code/regional_analysis/` (PDF Table A10) |
| A8 | Do the trends differ by subgroup? | `code/hetero_trends/` (PDF Table A12) |
| A9 | Occupation shares — 10 groups | `code/occ_shares/` (PDF Table A2) |
| A10 | Occupation shares — 25 groups | `code/occ_shares/` (PDF Table A3) |
| A11 | Father occupation across Nobel fields | Per-field occupation shares from `data/nobelists_analysis.csv` and `code/occ_shares/` |
| A12 | Father ranks by birth cohort | `code/main_binscatter_ranks/` (PDF Figure A2) |
| A13 | Laureates from below the 80th / 90th percentile | `code/other_rank_functions/` (PDF Figure A3) |
| A14 | Robustness to alternate codings | `code/main_robust/` (PDF Table A6) |
| A15 | Global Rank Estimates: Robustness to National Occupation Distribution Adjustment | `code/main_spec/` (PDF Table A7) |
| A16 | Countries in each region | Birth-country regions from `data/nobelists_analysis.csv` (adapted from PDF Table A11) |
| A17 | Father occupations in detail | `code/occ_shares/` (detailed occupation shares) |
| A18 | The field match across definitions | `code/parent_field_match/parent_field_perm_test.py` (PDF Figure A4) |
| A19 | Parent field vs. laureate field | `code/parent_field_match/parent_field_match_graphs.py` (PDF Figure A5) |

**Not reproduced by code in this package:**
- Table A9 (gender gap, alternate codings): not yet ported.
- Table A11 (countries in each region): a reference list. Each laureate's
  region is in the `bloc` column of `data/nobelists_analysis.csv`.
- The advisor-tree comparison: relies on advisor-linkage data not included here.

**Supplementary analysis** (ported from the authors' original code, not a
numbered exhibit in the paper): `gender_analysis` reproduces father-rank
trends by gender, robust Wald tests of equal trend slopes, and Wilcoxon
distribution tests. Panel A6 reports the trends and slope-equality p-values.

**Known differences from the published tables:**
- The permutation test (Figure 3, Table 3, Figure A4) uses a fixed NumPy
  seed, so it reproduces exactly from run to run. Its random draws differ
  from the original Stata run, so simulated p-values can differ slightly
  from the printed ones.
- Table A4's census shares are approximate. See the ACCURACY note in
  `code/occ_representation_change/occ_representation_change.py`.

## Data sources

Laureates and prize years cover all Nobel Prizes in Physics, Chemistry,
Physiology or Medicine, and Economics, 1901–2023. Fathers' occupations were
compiled by the authors from biographical sources and checked with an
LLM-assisted web search; `data/laureates_grounded_search.csv` records the
sources and reasoning for each laureate. Occupations are coded to the IPUMS
`occ1950` scheme and ranked using historical census microdata from IPUMS.
Occupation labels have been normalised to sentence case, with spelling
corrections.

## Citing

Please cite the paper (see `CITATION.cff`). Work that uses the census-derived
files must also cite IPUMS USA:

> Ruggles, Steven, Sarah Flood, Matthew Sobek, et al. IPUMS USA [dataset].
> Minneapolis, MN: IPUMS. https://usa.ipums.org

## Your own analysis

Start from `code/examples/father_rank_by_decade/`. It reads
`data/nobelists_analysis.csv`, asks a question the paper doesn't, and writes
its result to its own `output/` folder. `data/codebook.csv` lists every column.
