SPB Git

spb/wp29_uqo

Public
2.7 KB · 66 lines python
1"""F2-conf-03: Monte Carlo coverage of OLS CIs under heteroskedasticity.2Run from workspace root: ~/wp29/venv/bin/python out/analysis.py"""3import json, os4import numpy as np, pandas as pd5from scipy import stats67SEED = 202610308ALPHA, BETA, R, LEVEL = 1.0, 0.5, 2000, 0.95910d = pd.read_csv("data/design.csv")11issues = []12n_rows = len(d)13assert list(d.columns) == ["i", "x", "sigma"]14if d.isna().any().any(): issues.append({"issue": "missing values", "handling": "none expected; would abort"})15if d["i"].duplicated().any(): issues.append({"issue": "duplicate indices", "handling": "reported"})16if (d["sigma"] <= 0).any(): issues.append({"issue": "non-positive sigma", "handling": "reported"})17x = d["x"].to_numpy(float); sig = d["sigma"].to_numpy(float); n = len(x)18assert n == 301920X = np.column_stack([np.ones(n), x])21XtXi = np.linalg.inv(X.T @ X)22A = XtXi @ X.T                      # 2 x n, beta_hat = A y23# exact variance of slope: sum a_i^2 sigma_i^224sd_exact = float(np.sqrt(np.sum(A[1] ** 2 * sig ** 2)))2526rng = np.random.default_rng(SEED)27eps = rng.standard_normal((R, n))28Y = ALPHA + BETA * x[None, :] + sig[None, :] * eps   # R x n29B = Y @ A.T                                           # R x 230E = Y - B @ X.T                                       # residuals31s2 = (E ** 2).sum(1) / (n - 2)32se_conv = np.sqrt(s2 * XtXi[1, 1])33hc0 = (E ** 2) @ (A[1] ** 2)                          # sandwich slope element34se_hc1 = np.sqrt(hc0 * n / (n - 2))35tc = stats.t.ppf(0.5 + LEVEL / 2, n - 2)36bh = B[:, 1]37cov_conv = float(np.mean(np.abs(bh - BETA) <= tc * se_conv))38cov_hc1 = float(np.mean(np.abs(bh - BETA) <= tc * se_hc1))39mcse_nom = np.sqrt(LEVEL * (1 - LEVEL) / R)40undercov = bool(cov_conv < LEVEL - 3 * mcse_nom)4142res = {43    "task_id": "F2-conf-03",44    "coverage_conventional": cov_conv,45    "coverage_hc1": cov_hc1,46    "sd_beta_exact": sd_exact,47    "sd_beta_mc": float(np.std(bh, ddof=1)),48    "mean_se_conventional": float(se_conv.mean()),49    "conventional_ci_undercovers": undercov,50    "n_replications": R,51    "n_obs_per_replication": n,52    "feasibility": "complete",53    "feasibility_reason": None,54    "data_issues": issues,55    "n_input_rows": {"design.csv": n_rows},56    "random_seed": SEED,57}58os.makedirs("out", exist_ok=True)59with open("out/results.json", "w") as f: json.dump(res, f, indent=2)60# auxiliary diagnostics (printed, not part of results.json)61print(json.dumps(res, indent=2))62print("t crit", tc, "MCSE at 0.95", mcse_nom,63      "MCSE conv", np.sqrt(cov_conv*(1-cov_conv)/R), "MCSE hc1", np.sqrt(cov_hc1*(1-cov_hc1)/R),64      "mean se_hc1", se_hc1.mean(), "naive sd formula", np.sqrt(np.mean(sig**2)*XtXi[1,1]),65      "E[se_conv^2] exact sqrt", np.sqrt(XtXi[1,1]*np.sum(sig**2*np.diag(np.eye(n)-X@XtXi@X.T))/(n-2)))66
Files · main
Menu

Theme