Skip to content

chc.estimators

Stability tier: evolving.

Pluggable causal-effect estimators: one Strategy interface, thin backend adapters.

CHC's identity is control + pessimism + benchmark on top of causal effects, not a home-grown causal library. A controller only needs a scalar interventional slope d x_next / d u; this module lets that number come from whichever backend is best, behind a single interface (CausalEffectEstimator):

  • built-ins (BackdoorOLS, IV2SLS, DoubleML) — zero-dependency, thin wrappers over chc.causal; the default when you do not want extra installs;
  • adapters over mature libraries (EconMLDoubleML -> EconML) — lazy-imported, never a hard dependency. EconML 0.17 installs beside pandas>=3 on Python 3.12 and 3.14 (checked 2026-09-28), but it brings numba, sparse, statsmodels, shap and lightgbm with it, for one adapter over a pure-JAX core. DoWhy 0.14 declares <3.14. Install either yourself and pass the class in.

Richer backends may also return a heterogeneous cate(x) and diagnostics; the controller ignores what it does not need, so every backend is swappable without touching the control code.

EffectEstimate dataclass

What a controller needs (effect), plus optional heterogeneity and diagnostics.

effect is the average interventional slope d x_next / d u consumed by certainty-equivalent or MPC control. cate maps covariates to a per-unit effect where the backend supplies it (EconML); diagnostics carries backend extras (t-stat, robustness, Qini).

CausalEffectEstimator

Bases: Protocol

Estimate the interventional effect of treatment on outcome given covariates.

covariates is the conditioning set (backdoor adjustment set / DML nuisances / EconML X). Every estimator here refuses, with ValueError, a column named in two roles -- the treatment as the outcome or as a covariate, the outcome as a covariate, a covariate twice: read in both, the treatment is partialled out of itself, or the outcome explained by itself.

BackdoorOLS dataclass

Backdoor adjustment: OLS of outcome on [treatment, *covariates] and an intercept.

IV2SLS dataclass

Two-stage least squares using instrument for a latent confounder (built-in).

Both stages condition on the column x, as chc.causal.estimate_effect_iv does, and covariates is not read, so the treatment, the outcome and the instrument must each be a column other than x. An instrument that does not move the treatment beyond what x explains leaves the effect not identified, and is refused with ValueError.

diagnostics["instrument_relevance"], experimental, is the partial correlation of the treatment and the instrument given x, in absolute value: how far the instrument moves the treatment, which grades a weak instrument and is not a test.

DoubleML dataclass

Cross-fitted, Neyman-orthogonal Double ML with polynomial nuisances (built-in).

The nuisances are chc.causal.dml_point_and_se's, built on the centred and scaled covariates with the intercept free of the ridge, so ridge reads the same in any units of the covariates and at any level of them, of the treatment and of the outcome.

RLearner dataclass

Nie-Wager R-learner for heterogeneous effects tau(x) (built-in; continuous treatment).

Cross-fits nuisances m(x)=E[outcome|x] and e(x)=E[treatment|x] (polynomial-ridge), then fits a linear-in-features tau minimising the R-loss sum (y_res - tau(x)*t_res)^2 on the residualised data -- Neyman-orthogonal, so it recovers the CATE even under nonlinear confounding where a naive treatment-on-outcome regression is biased. Returns the average effect as effect and tau(x) as cate (call it on the covariate matrix). cate_degree=1 is linear heterogeneity; raise it for nonlinear tau.

ridge reads the same in any units of the covariates and the treatment, and at any level of the covariates, the treatment and the outcome: the nuisances and tau are built on the centred and scaled covariates, the nuisances' intercept takes no ridge, and the ridge on each coefficient of tau is scaled by its column's mean square in the R-loss, which has no intercept. cate takes the covariates in the caller's units.

EconMLDoubleML dataclass

Adapter over econml.dml.LinearDML (lazy import; requires econml installed).

Pass a pre-constructed EconML estimator via model (e.g. CausalForestDML(...)) to use any EconML DML variant; the default is LinearDML. Returns the ATE as effect and exposes EconML's heterogeneous effect(X) as cate.

DoWhyEstimator dataclass

Adapter over DoWhy's identify -> estimate workflow (lazy import; requires dowhy installed).

Builds a CausalModel with common_causes = covariates, identifies the estimand, and estimates it (backdoor linear regression by default). Pass another method_name for a different DoWhy estimator (e.g. propensity-score matching / weighting).