SPB Git

spb/wp35_uqo

Public
3.8 KB · 65 lines python
1"""Modern country-year panel: V-Dem v16 (institutions, outcomes) + Maddison 2023 (population, GDP per capita).23Variables fixed in research/preregistration.md §3 and the codebook readings recorded in research/measurement.md:4  K items: v2clrspct, v2stcritrecadm, v2cltrnslw, v2stfisccap, v2svstterr, v2elembcap5  D: Maddison `pop` (thousands) ; e_area (km2, 1886+)6  Outcomes (events in year t): Y4 civil war onset = e_civil_war 0->1 ; Y5 coup = e_coups >= 1 ;7           Y6 irregular regime end = last year of a regime (v2regidnr changes) whose v2regendtype is in {0,1,2,3,5,6,7,8}8  Covariates: Maddison gdppc, v2x_polyarchy, e_regionpol_6C9Crosswalk: ISO3 (`country_text_id` == `countrycode`); unmatched countries are listed in10data/metadata/crosswalk_vdem_maddison.csv and kept without Maddison values (no substitution from e_pop).11"""12from __future__ import annotations13from pathlib import Path14import numpy as np15import pandas as pd16import pyreadr1718ROOT = Path(__file__).resolve().parents[3]19VDEM = ROOT / "data" / "raw" / "vdem_v16_rdata" / "vdem_v16.RData"20MADD = ROOT / "data" / "raw" / "maddison_2023_xlsx" / "mpd2023_web.xlsx"21META = ROOT / "data" / "metadata"2223K_ITEMS = ["v2clrspct", "v2stcritrecadm", "v2cltrnslw", "v2stfisccap", "v2svstterr", "v2elembcap"]24IRREGULAR_END = {0, 1, 2, 3, 5, 6, 7, 8}25KEEP = ["country_name", "country_text_id", "country_id", "year", "e_regionpol_6C", "e_regionpol", "v2x_polyarchy",26        "e_civil_war", "e_miinterc", "e_coups", "e_pt_coup", "v2regendtype", "v2regint", "v2regdur", "e_pop", "e_area",27        "e_gdppc", "v2x_regime", "v2x_rule", "v2regidnr"] + K_ITEMS282930def build() -> dict[str, pd.DataFrame]:31    vd = pyreadr.read_r(VDEM)["vdem"]32    cols = [c for c in KEEP if c in vd.columns]33    v = vd[cols].copy()34    v["year"] = v.year.astype(int)35    md = pd.read_excel(MADD, sheet_name="Full data")36    md = md.rename(columns={"countrycode": "country_text_id", "pop": "maddison_pop", "gdppc": "maddison_gdppc"})37    md["year"] = md.year.astype(int)38    m = v.merge(md[["country_text_id", "year", "maddison_pop", "maddison_gdppc"]], on=["country_text_id", "year"], how="left")39    # crosswalk audit40    vset, mset = set(v.country_text_id.unique()), set(md.country_text_id.unique())41    cw = pd.DataFrame({"code": sorted(vset | mset)})42    cw["in_vdem"] = cw.code.isin(vset); cw["in_maddison"] = cw.code.isin(mset)43    names = v.drop_duplicates("country_text_id").set_index("country_text_id").country_name44    cw["vdem_name"] = cw.code.map(names)45    META.mkdir(parents=True, exist_ok=True)46    cw.to_csv(META / "crosswalk_vdem_maddison.csv", index=False)47    m = m.sort_values(["country_text_id", "year"]).reset_index(drop=True)48    g = m.groupby("country_text_id")49    # outcomes in year t50    cw_prev = g.e_civil_war.shift(1)51    m["y4_civilwar_onset"] = np.where(m.e_civil_war.isna() | cw_prev.isna(), np.nan,52                                      ((m.e_civil_war == 1) & (cw_prev == 0)).astype(float))53    m["y5_coup"] = np.where(m.e_coups.isna(), np.nan, (m.e_coups >= 1).astype(float))54    # v2regendtype is carried on every year of a regime (how that regime eventually ended; 13 = still exists).55    # The event is placed in the regime's LAST year: v2regidnr changes between t and t+1 (within country).56    next_id = g.v2regidnr.shift(-1)57    last_year = m.v2regidnr.notna() & next_id.notna() & (m.v2regidnr != next_id)58    m["regime_end_year"] = last_year.astype(float)59    m["y6_irregular_regime_end"] = np.where(m.v2regendtype.isna() | next_id.isna(), np.nan,60                                           (last_year & m.v2regendtype.isin(IRREGULAR_END)).astype(float))61    m["log_pop"] = np.log(m.maddison_pop.where(m.maddison_pop > 0))62    m["log_area"] = np.log(m.e_area.where(m.e_area > 0))63    m["log_gdppc"] = np.log(m.maddison_gdppc.where(m.maddison_gdppc > 0))64    return {"panel": m, "crosswalk": cw}65
Files · main
Menu

Theme