metacausal.CausalEnsemble

class metacausal.CausalEnsemble(methods=None, aggregation='median', outcome_type='auto')[source]

Bases: object

Ensemble of causal estimators with robust aggregation.

Orchestrates multiple causal ML methods and aggregates their treatment effect estimates. The median is the default aggregation rule, providing a 50% breakdown point against catastrophic failure of individual methods.

Parameters:
  • methods (list | None) –

    List of causal estimators. Accepts:

    • Objects implementing CausalEstimator protocol

    • EconML estimator instances (auto-detected and wrapped)

    • DoubleMLAdapter instances (explicit)

    • GenericATEAdapter or GenericCATEAdapter instances

    • Lists/tuples of 2 or 3 callables, auto-wrapped as GenericCATEAdapter

    If None, uses default_methods() — and which pool it returns depends on the outcome type detected at fit time.

  • aggregation (str | AggregationStrategy) – Aggregation strategy. Either a string alias ("median", "mean", "trimmed_mean", "cba") or a strategy object implementing AggregationStrategy.

  • outcome_type (str) – How to interpret Y. "auto" (default) detects from the value set of Y at fit time (metacausal.infer_outcome_type()): Y ⊆ {0, 1} or boolean is binary, otherwise continuous. "continuous" and "binary" force the corresponding interpretation. "binary" with non-binary Y raises; "continuous" with binary Y is silently accepted (a “give me the linear- probability ATE” request).

Outcome-type lifecycle: at fit time the ensemble resolves the outcome type from Y, materialises the right default pool if no methods were supplied, drops any component whose supported_outcome_types does not include the detected type (with one summary warning naming the drops), and validates each survivor’s nuisance configuration. For binary outcomes the estimand is the risk difference.

Examples

Fit two components and compute the ensemble ATE with a full-pipeline bootstrap. estimate() (not shown) offers a one-call fit + ate/bootstrap convenience wrapper.

>>> from metacausal import CausalEnsemble
>>> from metacausal.datasets import load_lalonde
>>> from metacausal.adapters import DoubleMLAdapter
>>> from econml.dml import CausalForestDML
>>> from doubleml import DoubleMLIRM
>>> from sklearn.ensemble import (
...     HistGradientBoostingClassifier, HistGradientBoostingRegressor,
... )
>>> X, T, Y = load_lalonde()
>>> ens = CausalEnsemble([
...     CausalForestDML(
...         model_y=HistGradientBoostingRegressor(max_iter=50),
...         model_t=HistGradientBoostingClassifier(max_iter=50),
...         discrete_treatment=True,
...         n_estimators=50,
...         n_jobs=1,
...     ),
...     DoubleMLAdapter(
...         DoubleMLIRM,
...         ml_g=HistGradientBoostingRegressor(max_iter=50),
...         ml_m=HistGradientBoostingClassifier(max_iter=50),
...     ),
... ])
>>> _ = ens.fit(X, T, Y, random_state=42)
>>> result = ens.ate()
>>> boot = ens.bootstrap(n_boot=5, random_state=42)  # small n_boot for a fast example

Methods

__init__

ate

Compute the ensemble ATE from fitted component models.

bootstrap

Bootstrap inference for ensemble ATE and CATE.

cate

Compute ensemble CATE from fitted component models.

disagreement

Pairwise disagreement heatmap between component CATEs on X.

estimate

Fit and compute ATE (and optionally bootstrap CIs) in one call.

fit

Fit all component methods on the given data.

summary

Return a formatted, multi-line summary of ensemble state.

weights

Bar chart of the fitted aggregation strategy's weights.

Attributes

cate_method_names

Names of component methods that support CATE.

method_names

Names of all component methods.

Details

ate(X=None, aggregation=None)[source]

Compute the ensemble ATE from fitted component models.

Parameters:
  • X (ndarray | None) – Covariate matrix for ATE evaluation. If None, uses the training covariates from fit().

  • aggregation (str | AggregationStrategy | None) – Optional override for the aggregation strategy. If None, uses the strategy from fit(). See cate() for full override semantics.

Returns:

AteEstimate with aggregated ATE and component estimates. For bootstrap CIs, use bootstrap().

Return type:

AteEstimate

bootstrap(X=None, n_boot=200, alpha=0.05, random_state=None, n_jobs=1, method='nonparametric', subsample_size=0.5)[source]

Bootstrap inference for ensemble ATE and CATE.

Resamples training data, refits the entire pipeline (component models and aggregation weights) per replicate, and computes percentile CIs for both ATE and CATE.

For SupervisedStrategy, each replicate re-runs the full cross-fitting and nuisance estimation on the resampled data — this is the honest bootstrap but is expensive: B × Q × K adapter fits plus B nuisance fits. Use lightweight nuisance models (set propensity_model and outcome_model on the strategy) when running many replicates.

Parameters:
  • X (ndarray | None) – Covariates for prediction. If None, uses X_train.

  • n_boot (int) – Number of bootstrap replicates.

  • alpha (float) – Significance level (default 0.05 → 95% CIs).

  • random_state (int | None) – Seed for bootstrap resampling. If None and fit() was called with a seed, bootstrap seeds are derived deterministically from the fit seed.

  • n_jobs (int) – Parallel workers for bootstrap replicates. 1 = sequential, -1 = all cores. Requires joblib. Each replicate’s inner cross-fitting and nuisance estimation run sequentially — bootstrap is treated as the outermost parallel level to avoid oversubscription.

  • method (str) – Resampling scheme. "nonparametric" (default): n-out-of-n with replacement, the standard Efron bootstrap. Replicates contain duplicates of the original units, which can leak across cross-fit folds inside DML-style components and supervised aggregation wrappers, weakening the orthogonality argument those components rely on. "subsample": m-out-of-n without replacement, T-stratified. Eliminates duplicates so any downstream cross-fit (the supervised pipeline’s outer loop, every adapter’s internal cross-fit, supervised aggregation CV) stays honest. CIs use the Politis–Romano (1994) scaled-percentile correction: θ̂ + sqrt(m/n) * percentile(T_m - θ̂).

  • subsample_size (float | int) – Subsample size when method="subsample". Float in (0, 1) is interpreted as a fraction of n; int is interpreted as m directly. Must satisfy 1 ≤ m < n. The default 0.5 (m = n/2) is a practical compromise between preserving sample size for the components’ nuisance fits and giving the subsampling correction enough room to work; smaller m is justified theoretically but increases replicate failure rates and finite-sample bias of the components. Ignored when method="nonparametric".

Returns:

BootstrapResult with ATE and CATE point estimates, CIs, and bootstrap distributions.

Return type:

BootstrapResult

cate(X=None, aggregation=None)[source]

Compute ensemble CATE from fitted component models.

Only methods with supports_cate=True participate. The aggregation strategy determines how component CATE vectors are combined (pointwise rule, agreement-based weights, or outcome-supervised weights).

Parameters:
  • X (ndarray | None) – Covariate matrix for CATE prediction, shape (n, p). If None, uses the training covariates from fit().

  • aggregation (str | AggregationStrategy | None) – Optional override for the aggregation strategy. If None, uses the strategy from fit(). Accepts a string alias, a PointwiseStrategy (stateless), an AgreementStrategy (weights recomputed from cached training CATE predictions), or a SupervisedStrategy (weights recomputed from cached OOF predictions — requires a prior supervised fit). The override object is mutated (weights populated). Pass a fresh instance per call if you need independent weight objects.

Returns:

CateEstimate with aggregated CATE and component estimates. For bootstrap CIs, use bootstrap().

Return type:

CateEstimate

disagreement(X, *, ax=None, metric='spearman', cluster=False, annotate=True)[source]

Pairwise disagreement heatmap between component CATEs on X.

Thin wrapper around metacausal.plots.disagreement(); see there for the full parameter reference. Requires the plots extra (pip install 'metacausal[plots]').

Returns:

matplotlib Axes the plot was drawn on.

Parameters:
  • X (np.ndarray)

  • ax (Axes | None)

  • metric (Literal['spearman', 'pearson', 'rmse'])

  • cluster (bool)

  • annotate (bool)

Return type:

Axes

estimate(X, T, Y, n_boot=0, alpha=0.05, random_state=None, n_jobs=1, method='nonparametric', subsample_size=0.5, **kwargs)[source]

Fit and compute ATE (and optionally bootstrap CIs) in one call.

Parameters:
  • X (ndarray) – Covariate matrix, shape (n, p).

  • T (ndarray) – Treatment vector, shape (n,).

  • Y (ndarray) – Outcome vector, shape (n,).

  • n_boot (int) – Number of bootstrap replicates. 0 = point estimate only.

  • alpha (float) – Significance level for bootstrap CIs (default 0.05 → 95%).

  • random_state (int | None) – Seed for reproducibility.

  • n_jobs (int) – Parallel workers. Routed to the outermost active level: when n_boot > 0, bootstrap is parallelized and the inner fit() runs sequentially; otherwise the supervised cross-fitting / component-fit loop is parallelized.

  • method (str) – Bootstrap resampling scheme; see bootstrap().

  • subsample_size (float | int) – Subsample size when method="subsample"; see bootstrap().

  • **kwargs – Forwarded to each method’s fit() call.

Returns:

AteEstimate when n_boot=0, BootstrapResult when n_boot > 0.

Return type:

AteEstimate | BootstrapResult

fit(X, T, Y, random_state=None, n_jobs=1, **kwargs)[source]

Fit all component methods on the given data.

Parameters:
  • X (ndarray) – Covariate matrix, shape (n, p).

  • T (ndarray) – Treatment vector, shape (n,).

  • Y (ndarray) – Outcome vector, shape (n,).

  • random_state (int | None) – Seed for reproducibility. Controls component estimator randomness.

  • n_jobs (int) – Parallel workers for component fits. For a SupervisedStrategy, this also parallelizes the Q×K cross-fitting loop. Inner levels always run sequentially; if called inside an already-parallel context, this value is ignored.

  • **kwargs – Forwarded to each adapter’s fit() call.

Returns:

self (for chainingens.fit(X, T, Y).ate()).

Return type:

CausalEnsemble

summary()[source]

Return a formatted, multi-line summary of ensemble state.

Return type:

str

weights(*, ax=None, on_uniform='warn', sort=True)[source]

Bar chart of the fitted aggregation strategy’s weights.

Thin wrapper around metacausal.plots.weights(); see there for the full parameter reference. Requires the plots extra (pip install 'metacausal[plots]'). Raises ValueError if the fitted aggregation strategy is pointwise (no weights to plot).

Returns:

matplotlib Axes the plot was drawn on.

Parameters:
  • ax (Axes | None)

  • on_uniform (Literal['warn', 'error', 'ignore'])

  • sort (bool)

Return type:

Axes

property cate_method_names: list[str]

Names of component methods that support CATE.

property method_names: list[str]

Names of all component methods.