SPB Git

spb/wp29_uqo

Public
10.5 KB · 189 lines python
1"""F4-conf-01: extract printed treatment effects/uncertainty from two source extracts.2Reads only data/; writes out/results.json. No randomness."""3import json, re, os, hashlib4from decimal import Decimal56ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))7D = os.path.join(ROOT, "data")8DCR_ID, RI_ID = "arxiv-2609.27732v1", "arxiv-2606.14621v1"9Z = 1.96  # normal critical value for 95% two-sided1011def read(p):12    with open(os.path.join(D, p), encoding="utf-8") as f:13        return f.read()1415def wc_l(p):16    with open(os.path.join(D, p), "rb") as f:17        return f.read().count(b"\n")1819dcr = read(f"sources/{DCR_ID}.txt").split("\n")20ri = read(f"sources/{RI_ID}.txt").split("\n")2122def table_block(lines, title_prefix):23    i = next(k for k, l in enumerate(lines) if l.startswith(title_prefix))24    j = next(k for k in range(i + 1, len(lines)) if lines[k].startswith("Note:"))25    return [(k + 1, lines[k]) for k in range(i, j) if lines[k].strip()]2627def num(s):28    """Parse printed number keeping printed decimals; returns (float, printed str)."""29    s = s.strip().replace("$", "").replace(",", "").replace("*", "").strip("()")30    s = s.replace("%", "")31    return (int(s) if re.fullmatch(r"-?\d+", s) else float(s)), s3233def dcr_cell(block, row, col):34    header = [c.strip() for c in block[1][1].split("|")]35    ci = header.index(col)36    for idx, (ln, l) in enumerate(block):37        cells = [c.strip() for c in l.split("|")]38        if cells[0] == row:39            raw = cells[ci]40            print(f"[{DCR_ID} line {ln}] {l}")41            out = {"value": num(raw)[0], "stars": raw.count("*"), "raw": raw}42            nxt = block[idx + 1] if idx + 1 < len(block) else None43            if nxt and nxt[1].lstrip().startswith("| ("):44                print(f"[{DCR_ID} line {nxt[0]}] {nxt[1]}")45                se_raw = [c.strip() for c in nxt[1].split("|")][ci]46                out["se"] = num(se_raw)[0]; out["se_raw"] = se_raw47            return out48    raise KeyError(row)4950t6 = table_block(dcr, "Table 6:")51t7 = table_block(dcr, "Table 7:")52for ln, l in t6[:2] + t7[:2]:53    print(f"[{DCR_ID} line {ln}] {l}")5455a5 = dcr_cell(t6, "ATT", "5 km"); a3 = dcr_cell(t6, "ATT", "3 km")56obs5 = dcr_cell(t6, "Observations", "5 km")57narc3 = dcr_cell(t7, "Narcotics", "3 km")58fat1 = dcr_cell(t7, "Drug-related (fatal)", "1 km")59hiv5 = dcr_cell(t7, "HIV", "5 km")6061# exact p-value search: any "p=" / "p-value" in DCR extract tied to HIV?62dcr_text = "\n".join(dcr)63p_hits = [l for l in dcr if re.search(r"p\s*=\s*0?\.\d", l)]64hiv_p = None  # stars only (none on HIV 5 km); no exact p-value printed65print(f"DCR lines with an exact 'p=' value: {len(p_hits)}")6667# derived CI (Table 6, 5 km); round to 4 dp (one more than the printed 3 dp)68ci_lo = round(a5["value"] - Z * a5["se"], 4)69ci_hi = round(a5["value"] + Z * a5["se"], 4)7071# RESEA Table 272t2_hdr = next(k for k, l in enumerate(ri) if l.startswith("Outcome | Treatment | Control"))73header = [c.strip() for c in ri[t2_hdr].split("|")]74print(f"[{RI_ID} line {t2_hdr+1}] {ri[t2_hdr]}")75def ri_row(label):76    for k in range(t2_hdr + 1, len(ri)):77        cells = [c.strip() for c in ri[k].split("|")]78        if cells[0] == label:79            print(f"[{RI_ID} line {k+1}] {ri[k]}")80            return dict(zip(header, cells))81    raise KeyError(label)82ATE = "Average treatment effect estimate"83def parse_effect(cell):84    est = cell.split(";")[0]85    est = re.sub(r"\s*(pp|weeks|wks)$", "", est.strip())86    m = re.search(r"95% CI: \[(.+?),\s*(-?[\d.]+(?:,\d{3})*(?:\.\d+)?)\]", cell)87    lo, hi = m.group(1), m.group(2)88    se_printed = bool(re.search(r"\bSE\b|standard error", cell, re.I))89    return num(est)[0], num(lo)[0], num(hi)[0], se_printed90w = ri_row("Wage"); r = ri_row("Reemployment"); u = ri_row("Weeks on UI")91w_ate, w_lo, w_hi, w_se_printed = parse_effect(w[ATE])92r_ate, _, _, _ = parse_effect(r[ATE])93u_ate, u_lo, u_hi, _ = parse_effect(u[ATE])94ctrl_mean = num(w["Control"].split("(")[0])[0]95w_se = round((w_hi - w_lo) / (2 * Z), 2)9697S6 = f"{DCR_ID} | Table 6"; S7 = f"{DCR_ID} | Table 7"; S2 = f"{RI_ID} | Table 2"98loc = {99 "dcr_att_5km": f'{S6} | row "ATT" | column "5 km"',100 "dcr_att_5km_se": f'{S6} | row "ATT" (standard error line in parentheses) | column "5 km"',101 "dcr_att_3km": f'{S6} | row "ATT" | column "3 km"',102 "dcr_att_3km_se": f'{S6} | row "ATT" (standard error line in parentheses) | column "3 km"',103 "dcr_obs_5km": f'{S6} | row "Observations" | column "5 km"',104 "dcr_narcotics_att_3km": f'{S7} | row "Narcotics" | column "3 km"',105 "dcr_narcotics_att_3km_se": f'{S7} | row "Narcotics" (standard error line in parentheses) | column "3 km"',106 "dcr_fatal_att_1km": f'{S7} | row "Drug-related (fatal)" | column "1 km"',107 "dcr_fatal_att_1km_se": f'{S7} | row "Drug-related (fatal)" (standard error line in parentheses) | column "1 km"',108 "dcr_hiv_att_5km": f'{S7} | row "HIV" | column "5 km"',109 "dcr_hiv_att_5km_se": f'{S7} | row "HIV" (standard error line in parentheses) | column "5 km"',110 "dcr_hiv_att_5km_p_value": f"not reported in {DCR_ID} (Table 7 gives only significance stars; the HIV 5 km cell has none)",111 "dcr_att_5km_ci_low": f'{S6} | row "ATT" | column "5 km" | derived from printed ATT and SE (normal, 1.96)',112 "dcr_att_5km_ci_high": f'{S6} | row "ATT" | column "5 km" | derived from printed ATT and SE (normal, 1.96)',113 "ri_wage_ate": f'{S2} | row "Wage" | column "Average treatment effect estimate"',114 "ri_wage_ate_ci_low": f'{S2} | row "Wage" | column "Average treatment effect estimate" (95% CI lower bound)',115 "ri_wage_ate_ci_high": f'{S2} | row "Wage" | column "Average treatment effect estimate" (95% CI upper bound)',116 "ri_wage_ate_se_derived": f'{S2} | row "Wage" | column "Average treatment effect estimate" | derived from printed 95% CI (width / (2 x 1.96)); SE not reported in {RI_ID}',117 "ri_control_mean_wage": f'{S2} | row "Wage" | column "Control"',118 "ri_reemployment_ate_pp": f'{S2} | row "Reemployment" | column "Average treatment effect estimate"',119 "ri_weeks_ui_ate": f'{S2} | row "Weeks on UI" | column "Average treatment effect estimate"',120 "ri_weeks_ui_ate_ci_low": f'{S2} | row "Weeks on UI" | column "Average treatment effect estimate" (95% CI lower bound)',121 "ri_weeks_ui_ate_ci_high": f'{S2} | row "Weeks on UI" | column "Average treatment effect estimate" (95% CI upper bound)',122}123124issues = [125 {"issue": f"{DCR_ID}: Table 6 prints SE (0.210) for the 5 km ATT -0.431**, while Appendix Table A19 (CS-DR column) prints the same ATT with SE (0.218).",126  "handling": "Used Table 6 value (0.210) as the key definition names Table 6; discrepancy reported."},127 {"issue": f"{DCR_ID}: Tables 6/7 and Figure 6 state 608 never-treated control regions, the A19 note states 640; the Table 6 observation counts (16,175/16,875/17,250) equal 25 x (640 + 7/35/50 treated regions), i.e. consistent with 640 controls.",128  "handling": "Observation count reported as printed (17250); inconsistency not resolvable from the extract, reported only."},129 {"issue": f"{DCR_ID}: abstract says fatal hospitalizations 'fall by 35%', whereas Table 7 fatal 5 km ATT -0.354 log points implies about -29.8% (Section 6.1 says ~30%); prose also calls HIV estimates 'close to zero' though 3/5 km ATTs are -0.239/-0.340.",130  "handling": "Prose not used; table values extracted as printed."},131 {"issue": f"{RI_ID}: prose reports the weeks-on-UI CI as magnitudes [1.75 weeks, 2.24 weeks]; Table 2 prints [-2.24, -1.75]. Prose also has a rendering defect 'p ¡ 0.001'.",132  "handling": "Table 2 values used (lower bound -2.24 first)."},133]134135res = {136 "task_id": "F4-conf-01",137 "dcr_att_5km": a5["value"], "dcr_att_5km_se": a5["se"],138 "dcr_att_3km": a3["value"], "dcr_att_3km_se": a3["se"],139 "dcr_obs_5km": int(obs5["value"]),140 "dcr_narcotics_att_3km": narc3["value"], "dcr_narcotics_att_3km_se": narc3["se"],141 "dcr_fatal_att_1km": fat1["value"], "dcr_fatal_att_1km_se": fat1["se"],142 "dcr_hiv_att_5km": hiv5["value"], "dcr_hiv_att_5km_se": hiv5["se"],143 "dcr_hiv_att_5km_p_value": hiv_p,144 "dcr_hiv_att_5km_significant_10pct": hiv5["stars"] >= 1,145 "dcr_att_5km_ci_low": ci_lo, "dcr_att_5km_ci_high": ci_hi,146 "ri_wage_ate": w_ate, "ri_wage_ate_ci_low": w_lo, "ri_wage_ate_ci_high": w_hi,147 "ri_wage_ate_se_reported": w_se_printed,148 "ri_wage_ate_se_derived": w_se,149 "ri_control_mean_wage": ctrl_mean,150 "ri_reemployment_ate_pp": r_ate,151 "ri_weeks_ui_ate": u_ate, "ri_weeks_ui_ate_ci_low": u_lo, "ri_weeks_ui_ate_ci_high": u_hi,152 "locators": loc,153 "derivation_notes": {154  "dcr_att_5km_ci": "Normal (Wald) 95% CI: ATT +/- 1.96 x SE using Table 6 printed ATT -0.431 and SE 0.210 (clustered SE, large-sample normal approximation); rounded to 4 decimals.",155  "ri_wage_ate_se": "SE = (upper - lower) / (2 x 1.96) using Table 2 printed 95% CI [166, 2,141]; assumes a symmetric normal-based CI (printed CI is symmetric around 1,153 to within rounding: 987 vs 988); rounded to 2 decimals. Using 2.0 instead would give 493.75."},156 "feasibility": "complete",157 "feasibility_reason": None,158 "data_issues": issues,159 "n_input_rows": {"README.md": wc_l("README.md"),160                  f"sources/{DCR_ID}.txt": wc_l(f"sources/{DCR_ID}.txt"),161                  f"sources/{RI_ID}.txt": wc_l(f"sources/{RI_ID}.txt")},162 "n_analysed": 25,163 "random_seed": None,164}165# baseline: cruder "2-sigma" convention for the two derived quantities (sensitivity reference)166res["baseline_dcr_att_5km_ci_2se"] = [round(a5["value"] - 2.0 * a5["se"], 4), round(a5["value"] + 2.0 * a5["se"], 4)]167res["baseline_ri_wage_ate_se_2se"] = round((w_hi - w_lo) / 4.0, 2)168# printed strings (JSON numbers drop trailing zeros, e.g. 0.210 -> 0.21)169res["printed_values"] = {170 "dcr_att_5km": a5["raw"], "dcr_att_5km_se": a5["se_raw"],171 "dcr_att_3km": a3["raw"], "dcr_att_3km_se": a3["se_raw"],172 "dcr_obs_5km": obs5["raw"],173 "dcr_narcotics_att_3km": narc3["raw"], "dcr_narcotics_att_3km_se": narc3["se_raw"],174 "dcr_fatal_att_1km": fat1["raw"], "dcr_fatal_att_1km_se": fat1["se_raw"],175 "dcr_hiv_att_5km": hiv5["raw"], "dcr_hiv_att_5km_se": hiv5["se_raw"],176 "ri_wage_cell": w[ATE], "ri_control_wage_cell": w["Control"],177 "ri_reemployment_cell": r[ATE], "ri_weeks_ui_cell": u[ATE],178}179# consistency diagnostics (printed only)180import math181zw = w_ate / w_se182print(f"Check: wage ATE z={zw:.3f}, implied two-sided normal p={math.erfc(abs(zw)/math.sqrt(2)):.4f} (printed p=0.022)")183print(f"Check: DCR 5km |t|={abs(a5['value'])/a5['se']:.3f} (printed **, i.e. p<0.05)")184print(f"Check: HIV 5km |t|={abs(hiv5['value'])/hiv5['se']:.3f} (no star)")185os.makedirs(os.path.join(ROOT, "out"), exist_ok=True)186with open(os.path.join(ROOT, "out", "results.json"), "w") as f:187    json.dump(res, f, indent=2, ensure_ascii=False)188print(json.dumps({k: v for k, v in res.items() if k not in ("locators", "derivation_notes", "data_issues")}, indent=1))189
Files · main
Menu

Theme