Source code for moderndid.diddynamic.container

"""Result container for the dynamic covariate balancing estimator."""

from __future__ import annotations

import math
from typing import NamedTuple

import polars as pl

from moderndid.core.maketables import build_single_coef_table
from moderndid.core.result import extract_vcov_info


[docs] class DynBalancingResult(NamedTuple): r"""Container for dynamic covariate balancing treatment effect estimates. Stores point estimates, variances, and diagnostic information produced by the dynamic covariate balancing estimator. The average treatment effect is defined as .. math:: \text{ATE} = \mu_1 - \mu_2 where :math:`\mu_1` and :math:`\mu_2` are the potential outcome estimates under the two treatment histories *ds1* and *ds2*. This class implements the ``maketables`` plug-in interface for publication-quality tables. See :ref:`publication_tables`. Attributes ---------- att : float The ATE point estimate (:math:`\mu_1 - \mu_2`). var_att : float Variance of the ATE. mu1 : float Potential outcome estimate under *ds1*. mu2 : float Potential outcome estimate under *ds2*. var_mu1 : float Variance of *mu1*. var_mu2 : float Variance of *mu2*. robust_quantile : float Robust chi-squared critical value for inference. gaussian_quantile : float Gaussian critical value for inference. gammas : dict Balancing weights per treatment history (keys ``'ds1'``, ``'ds2'``). coefficients : dict LASSO coefficients per treatment history. imbalances : dict Covariate imbalance measures. estimation_params : dict Standard moderndid metadata (observation count, variable names, etc.). References ---------- .. [1] Viviano, D. and Bradic, J. (2026). "Dynamic covariate balancing: estimating treatment effects over time with potential local projections." *Biometrika*, asag016. https://doi.org/10.1093/biomet/asag016 """ #: The ATE point estimate. att: float #: Variance of the ATE. var_att: float #: Potential outcome estimate under ds1. mu1: float #: Potential outcome estimate under ds2. mu2: float #: Variance of mu1. var_mu1: float #: Variance of mu2. var_mu2: float #: Robust chi-squared critical value. robust_quantile: float #: Gaussian critical value. gaussian_quantile: float #: Balancing weights per treatment history. gammas: dict #: LASSO coefficients per treatment history. coefficients: dict #: Covariate imbalance measures. imbalances: dict #: Standard moderndid metadata. estimation_params: dict = {} @property def se(self) -> float: """Standard error of the ATE estimate.""" return math.sqrt(self.var_att) @property def __maketables_coef_table__(self): """Return canonical coefficient table for maketables.""" return build_single_coef_table("ATE", self.att, self.se) def __maketables_stat__(self, key: str) -> int | float | str | None: """Return model-level statistics for maketables.""" if key == "N": n_obs = self.estimation_params.get("n_obs") if n_obs is not None: return int(n_obs) return None if key == "se_type": return "Analytical" if key == "balancing": raw = self.estimation_params.get("balancing") if raw is None: return None return raw.upper().replace("_", "-") if key == "method": return self.estimation_params.get("method") return None @property def __maketables_depvar__(self) -> str: """Return dependent variable label for maketables.""" return self.estimation_params.get("yname", "") @property def __maketables_fixef_string__(self) -> str | None: """Dynamic balancing results do not report fixed-effects formulas.""" return None @property def __maketables_vcov_info__(self) -> dict[str, str | None]: """Return variance-covariance metadata.""" return extract_vcov_info(self.estimation_params) @property def __maketables_stat_labels__(self) -> dict[str, str]: """Return custom labels for model-level statistics.""" return { "balancing": "Balancing", "method": "Method", } @property def __maketables_default_stat_keys__(self) -> list[str]: """Default model-level stats to display in ETable.""" return ["N", "se_type", "balancing"]
[docs] class DynBalancingHistoryResult(NamedTuple): r"""Container for treatment effects estimated over varying history lengths. Stores a summary table of ATEs, variances, and critical values for each treatment history length, plus the individual :class:`DynBalancingResult` objects for per-lag diagnostics. Attributes ---------- summary : polars.DataFrame One row per history length with columns ``period_length``, ``att``, ``var_att``, ``mu1``, ``var_mu1``, ``mu2``, ``var_mu2``, ``robust_quantile``, ``gaussian_quantile``. results : list[DynBalancingResult] Individual estimation results, ordered by ascending history length. """ summary: pl.DataFrame results: list
[docs] class DynBalancingHetResult(NamedTuple): r"""Container for treatment effects estimated across different final periods. Stores a summary table of ATEs, variances, and critical values for each final period, plus the individual :class:`DynBalancingResult` objects for per-period diagnostics. Attributes ---------- summary : polars.DataFrame One row per final period with columns ``final_period``, ``att``, ``var_att``, ``mu1``, ``var_mu1``, ``mu2``, ``var_mu2``, ``robust_quantile``, ``gaussian_quantile``. results : list[DynBalancingResult] Individual estimation results, ordered by ascending final period. """ summary: pl.DataFrame results: list