xcausal.CausalEnsemble

class xcausal.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(); its pool depends on the outcome type detected at fit time. Configure each member’s outcome, propensity, and effect models on the supplied estimator. See Default components and model configuration for resolved defaults and independent effect-model examples.

  • 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 (xcausal.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 xcausal import CausalEnsemble
>>> from xcausal.datasets import load_lalonde
>>> from xcausal.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.

For agreement and supervised strategies, the returned ATE is the arithmetic mean of the fitted ensemble CATE predictions over the rows of X, using the training covariates when X=None. AIPW pseudo-outcomes, when used to fit supervised weights, are training targets; their average is not the returned ensemble ATE.

Pointwise strategies aggregate the component ATE estimates directly. These semantics follow the selected aggregation override, or the strategy from fit() when no override is supplied.

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().

Warns:

RiskDifferenceWarning – On a resolved binary outcome, if the ensemble ATE is outside [-1, 1]. Agreement and supervised strategies also check the ensemble CATE used to compute the ATE, so a call can emit one CATE warning and one ATE warning. Estimates are returned unchanged; absence of a warning does not imply a bounded estimator.

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 subsampling with finite-population correction: θ̂ + sqrt(m/(n-m)) * percentile(T_m - θ̂). Here m is the resolved integer subsample size and n is the training size, independent of the evaluation grid size.

  • 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 retains about half the observations for fitting while leaving substantial subsample variation. This is a practical choice, not a general coverage guarantee. At exact half-sampling the CI multiplier is 1; above half it exceeds 1. Rounding can make half-sampling inexact for odd n. Ignored when method="nonparametric".

Return type:

BootstrapResult

Notes

The finite-population correction is motivated by regular asymptotic linearity: centered subsample variance is approximately proportional to 1/m - 1/n, whereas full-sample variance is proportional to 1/n. See Wu (1990) and Politis, Romano, and Wolf (2000), Remark 2.

Although subsamples are stratified on treatment, the multiplier uses the simple-random-sample factor, not a within-stratum correction. Applying it to CATE does not establish general CATE coverage or validity for nonregular aggregation. Without-replacement subsampling does not become the nonparametric bootstrap at m=n.

Returns:

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

Warns:

RiskDifferenceWarning – On a resolved binary outcome, at most one warning each for an original-fit ensemble ATE or CATE outside [-1, 1]. CATE warnings report the number of entries outside the bounds. Bootstrap replicates, confidence intervals, and component estimates are not checked or clipped. Absence of a warning does not imply a bounded estimator.

Parameters:
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().

Warns:

RiskDifferenceWarning – On a resolved binary outcome, one warning if any ensemble CATE entries are outside [-1, 1], reporting their count. Estimates are returned unchanged; absence of a warning does not imply a bounded estimator.

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 xcausal.plots.disagreement(); see there for the full parameter reference. Requires the plots extra (pip install 'xcausal[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 chaining – ens.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 xcausal.plots.weights(); see there for the full parameter reference. Requires the plots extra (pip install 'xcausal[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.