Source code for sw2023.core.results

"""
Result classes for SW2023 estimation outputs.

Each class wraps the numerical arrays returned by estimation methods and
provides human-readable __repr__ and summary() output.

Classes
-------
ConfintResult        : asymptotic confidence intervals (confint_asymptotic)
BootstrapResult      : bootstrap confidence intervals (SW2023Model.bootstrap)
SignificanceTestResult: wild bootstrap significance test (test_r3_significance)
"""

import numpy as np


# ─────────────────────────────────────────────────────────────────────────────
# ConfintResult
# ─────────────────────────────────────────────────────────────────────────────

[docs] class ConfintResult: """ Asymptotic confidence intervals from SW2023Model.confint_asymptotic(). Attributes ---------- phi_hat_ci : ndarray, shape (n, 2) Lower and upper confidence bounds for the frontier phi_hat(z). r1_ci : ndarray, shape (n, 2) CI for the first conditional moment r_1(z). r3_ci : ndarray, shape (n, 2) CI for the third conditional moment r_3(z). se_phi : ndarray, shape (n,) Standard errors for phi_hat(z). se_r1 : ndarray, shape (n,) Standard errors for r_1(z). se_r3 : ndarray, shape (n,) Standard errors for r_3(z). alpha : float Significance level used (1 - alpha is the confidence level). """ def __init__(self, phi_hat_ci, r1_ci, r3_ci, se_phi, se_r1, se_r3, alpha): self.phi_hat_ci = np.asarray(phi_hat_ci) self.r1_ci = np.asarray(r1_ci) self.r3_ci = np.asarray(r3_ci) self.se_phi = np.asarray(se_phi) self.se_r1 = np.asarray(se_r1) self.se_r3 = np.asarray(se_r3) self.alpha = float(alpha)
[docs] def __repr__(self): n = len(self.se_phi) conf = int(round((1 - self.alpha) * 100)) w = float(np.mean(self.phi_hat_ci[:, 1] - self.phi_hat_ci[:, 0])) return ( f"ConfintResult(n={n}, conf={conf}%, " f"mean_se_phi={self.se_phi.mean():.4f}, " f"mean_ci_width={w:.4f})" )
[docs] def summary(self): """Print a formatted summary of the asymptotic confidence intervals.""" n = len(self.se_phi) conf = int(round((1 - self.alpha) * 100)) w = self.phi_hat_ci[:, 1] - self.phi_hat_ci[:, 0] print("=" * 55) print(f"Asymptotic Confidence Intervals ({conf}%, n={n})") print("=" * 55) print(f"{'':30s} {'Mean':>8} {'Std':>8}") print("-" * 55) print(f"{'SE phi_hat':30s} {self.se_phi.mean():8.4f} " f"{self.se_phi.std():8.4f}") print(f"{'SE r1':30s} {self.se_r1.mean():8.4f} " f"{self.se_r1.std():8.4f}") print(f"{'SE r3':30s} {self.se_r3.mean():8.4f} " f"{self.se_r3.std():8.4f}") print(f"{'CI width phi_hat':30s} {w.mean():8.4f} " f"{w.std():8.4f}") print(f"{'CI lower phi_hat (mean)':30s} " f"{self.phi_hat_ci[:,0].mean():8.4f}") print(f"{'CI upper phi_hat (mean)':30s} " f"{self.phi_hat_ci[:,1].mean():8.4f}") print("=" * 55) print("Use .phi_hat_ci, .r1_ci, .r3_ci, .se_phi for arrays.")
# ───────────────────────────────────────────────────────────────────────────── # BootstrapResult # ─────────────────────────────────────────────────────────────────────────────
[docs] class BootstrapResult: """ Bootstrap confidence intervals from SW2023Model.bootstrap() or bootstrap_sw() / bootstrap_panel(). Attributes ---------- phi_hat_point : ndarray, shape (n,) Point estimates of the frontier phi_hat(z). phi_hat_ci : ndarray, shape (n, 2) Bootstrap CI for phi_hat(z). eff_mean_point : float Point estimate of the mean efficiency. eff_mean_ci : ndarray, shape (2,) Bootstrap CI for the mean efficiency. eff_individual_point : ndarray, shape (n,) Point estimates of individual efficiency scores. eff_individual_ci : ndarray, shape (n, 2) Bootstrap CI for individual efficiency scores. sigma_eta_point : ndarray, shape (n,) Point estimates of sigma_eta(z). sigma_eta_ci : ndarray, shape (n, 2) Bootstrap CI for sigma_eta(z). B : int Number of bootstrap draws used. alpha : float Significance level (1 - alpha is the confidence level). n_fail : int Number of bootstrap iterations that failed (should be 0). """ def __init__(self, phi_hat_point, phi_hat_ci, eff_mean_point, eff_mean_ci, eff_individual_point, eff_individual_ci, sigma_eta_point, sigma_eta_ci, B, alpha, n_fail=0): self.phi_hat_point = np.asarray(phi_hat_point) self.phi_hat_ci = np.asarray(phi_hat_ci) self.eff_mean_point = float(eff_mean_point) self.eff_mean_ci = np.asarray(eff_mean_ci) self.eff_individual_point = np.asarray(eff_individual_point) self.eff_individual_ci = np.asarray(eff_individual_ci) self.sigma_eta_point = np.asarray(sigma_eta_point) self.sigma_eta_ci = np.asarray(sigma_eta_ci) self.B = int(B) self.alpha = float(alpha) self.n_fail = int(n_fail)
[docs] def __repr__(self): conf = int(round((1 - self.alpha) * 100)) lo, hi = self.eff_mean_ci fail = f", n_fail={self.n_fail}" if self.n_fail > 0 else "" return ( f"BootstrapResult(B={self.B}, conf={conf}%, " f"mean_eff={self.eff_mean_point:.4f} " f"[{lo:.4f}, {hi:.4f}]{fail})" )
[docs] def summary(self): """Print a formatted summary of bootstrap confidence intervals.""" n = len(self.phi_hat_point) conf = int(round((1 - self.alpha) * 100)) phi_w = float(np.mean( self.phi_hat_ci[:, 1] - self.phi_hat_ci[:, 0])) eff_w = float(np.mean( self.eff_individual_ci[:, 1] - self.eff_individual_ci[:, 0])) lo, hi = self.eff_mean_ci print("=" * 55) print(f"Bootstrap Confidence Intervals (B={self.B}, {conf}%, n={n})") if self.n_fail > 0: print(f" Warning: {self.n_fail} iterations failed") print("=" * 55) print(f"Mean efficiency (point) : {self.eff_mean_point:.4f}") print(f"Mean efficiency ({conf}% CI) : [{lo:.4f}, {hi:.4f}]") print(f"Mean CI width — phi_hat : {phi_w:.4f}") print(f"Mean CI width — eff (indiv) : {eff_w:.4f}") print("=" * 55) print("Use .phi_hat_ci, .eff_individual_ci, .eff_mean_ci for arrays.")
# ───────────────────────────────────────────────────────────────────────────── # SignificanceTestResult # ─────────────────────────────────────────────────────────────────────────────
[docs] class SignificanceTestResult: """ Wild bootstrap significance test result from test_r3_significance(). Tests H0: E(epsilon^3 | Z) = const (spatially uniform inefficiency) against H1: E(epsilon^3 | Z) != const (heterogeneous inefficiency). Attributes ---------- statistic : float Observed test statistic T (variance of r_hat_3 relative to Var(eps^3)). p_value : float Bootstrap p-value. Small values (< 0.05) indicate heterogeneous inefficiency; large values indicate the null is not rejected. r3_hat : ndarray, shape (n,) Estimated third conditional moment r_hat_3(Z) from the original sample. T_boot : ndarray, shape (B,) Bootstrap distribution of the test statistic. B : int Number of bootstrap draws used. """ def __init__(self, statistic, p_value, r3_hat, T_boot, B): self.statistic = float(statistic) self.p_value = float(p_value) self.r3_hat = np.asarray(r3_hat) self.T_boot = np.asarray(T_boot) self.B = int(B)
[docs] def __repr__(self): sig = self.p_value < 0.05 label = "significant" if sig else "not significant" return ( f"SignificanceTestResult(T={self.statistic:.4f}, " f"p_value={self.p_value:.4f}, B={self.B}, {label})" )
[docs] def summary(self): """Print a formatted summary of the significance test.""" sig = self.p_value < 0.05 label = ("Reject H0 — heterogeneous inefficiency" if sig else "Do not reject H0 — uniform inefficiency") print("=" * 55) print("Wild Bootstrap Significance Test (PSVKZ 2024)") print(" H0: E(eps^3 | Z) = const (uniform inefficiency)") print("=" * 55) print(f"Test statistic T : {self.statistic:.6f}") print(f"p-value : {self.p_value:.4f} (B={self.B})") print(f"Bootstrap T range : [{self.T_boot.min():.4f}, " f"{self.T_boot.max():.4f}]") print(f"Conclusion : {label}") print("=" * 55)