xcausal.CausalEnsemble¶
- class xcausal.CausalEnsemble(methods=None, aggregation='median', outcome_type='auto')[source]¶
Bases:
objectEnsemble 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
CausalEstimatorprotocolEconML estimator instances (auto-detected and wrapped)
DoubleMLAdapterinstances (explicit)GenericATEAdapterorGenericCATEAdapterinstancesLists/tuples of 2 or 3 callables, auto-wrapped as
GenericCATEAdapter
If
None, usesdefault_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 implementingAggregationStrategy.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_typesdoes 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__Compute the ensemble ATE from fitted component models.
Bootstrap inference for ensemble ATE and CATE.
Compute ensemble CATE from fitted component models.
Pairwise disagreement heatmap between component CATEs on
X.Fit and compute ATE (and optionally bootstrap CIs) in one call.
Fit all component methods on the given data.
Return a formatted, multi-line summary of ensemble state.
Bar chart of the fitted aggregation strategy's weights.
Attributes
Names of component methods that support CATE.
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 whenX=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
aggregationoverride, or the strategy fromfit()when no override is supplied.- Parameters:
X (ndarray | None) – Covariate matrix for ATE evaluation. If
None, uses the training covariates fromfit().aggregation (str | AggregationStrategy | None) – Optional override for the aggregation strategy. If
None, uses the strategy fromfit(). Seecate()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:
- 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
Noneandfit()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 - θ̂). Heremis the resolved integer subsample size andnis 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 whenmethod="nonparametric".
- Return type:
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 to1/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:
- cate(X=None, aggregation=None)[source]¶
Compute ensemble CATE from fitted component models.
Only methods with
supports_cate=Trueparticipate. 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 fromfit().aggregation (str | AggregationStrategy | None) – Optional override for the aggregation strategy. If
None, uses the strategy fromfit(). 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:
- 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 theplotsextra (pip install 'xcausal[plots]').
- 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 innerfit()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"; seebootstrap().**kwargs – Forwarded to each method’s
fit()call.
- Returns:
AteEstimatewhenn_boot=0,BootstrapResultwhenn_boot > 0.- Return type:
- 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:
- 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 theplotsextra (pip install 'xcausal[plots]'). RaisesValueErrorif 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