metacausal.aggregation.RStacking¶
- class metacausal.aggregation.RStacking(split=<factory>, propensity_model=None, outcome_model=None, propensity_trim=0.01, fit_nuisance_fn=None)[source]¶
Bases:
SupervisedStrategyR-Stacking (Nie & Wager, 2021).
Finds a conic combination of component CATEs (plus a constant shift) that minimises the R-loss — the squared residual of the Robinson decomposition:
min_{b, c, α ≥ 0} Σ_i [Ỹ_i - b - (c + α·τ̂(X_i))·W̃_i]²
where Ỹ_i = Y_i - m̂(X_i) and W̃_i = W_i - ê(X_i) are Robinson residuals.
Reformulated as bounded linear least squares:
min ‖Az - y‖² s.t. lb ≤ z ≤ ub
- A(n, K+2) design matrix
col 0 : ones → z[0] = b (unconstrained) col 1 : W̃ → z[1] = c (unconstrained) cols 2..K+1: τ̂_k·W̃ → z[2:] = α (α_k ≥ 0)
y : Ỹ (n,)
Solved via
scipy.optimize.lsq_linear, which handles per-variable bounds directly.Output:
EnsembleWeights(weights=α̂, intercept=ĉ).b̂absorbs residual mean bias in m̂ and is discarded — it does not appear in CATE prediction.ĉis the estimated constant CATE shift; it becomes theinterceptfield ofEnsembleWeightsso thataggregatecorrectly computesĉ + α̂·τ̂(x).Key differences from CausalStacking / Q-Aggregation:
Conic constraint (α_k ≥ 0, no sum-to-one): weights are not probabilities. The ensemble prediction is not a convex combination of individual CATEs but can amplify or dampen any component.
Constant shift ĉ: the ensemble adds a global CATE offset, enabling it to correct for systematic under- or over-estimation by the component library.
R-loss rather than DR pseudo-outcome MSE: requires both m̂ and ê (not separately doubly robust).
Numerical note: When W̃_i ≈ 0 (highly accurate propensity model), the columns τ̂_k·W̃ are near-zero, providing little signal about the CATE. The solver may return α ≈ 0 with a large b. This is a fundamental limitation of R-loss in near-balanced settings, not an implementation bug.
- Parameters:
split (CrossFitSplit or TrainAvgSplit) – Data splitting strategy. Default: 5-fold cross-fitting.
propensity_model (sklearn classifier or None) – Model for P(T=1|X).
NoneselectsHistGradientBoostingClassifier.outcome_model (sklearn regressor / classifier or None) – Model for E[Y|X, T]. The marginal conditional mean m̂(x) is derived from this via m̂ = ê·μ̂₁ + (1-ê)·μ̂₀. For continuous Y, must be a regressor; for binary Y, must be a classifier (
predict_proba).Noneselects an outcome-type-appropriate default (HistGradientBoostingRegressororHistGradientBoostingClassifier).propensity_trim (float) – Clip propensity scores to [trim, 1-trim].
fit_nuisance_fn (Any)
Examples
>>> from sklearn.linear_model import LinearRegression >>> from sklearn.ensemble import HistGradientBoostingRegressor as HGBR >>> from metacausal import CausalEnsemble >>> from metacausal.adapters import GenericCATEAdapter >>> from metacausal.aggregation import RStacking >>> from metacausal.datasets import load_lalonde >>> X, T, Y = load_lalonde() >>> def fit_linear(X, T, Y, **kwargs): ... treated = T == 1 ... m1 = LinearRegression().fit(X[treated], Y[treated]) ... m0 = LinearRegression().fit(X[~treated], Y[~treated]) ... return (m1, m0) >>> def fit_hgb(X, T, Y, **kwargs): ... treated = T == 1 ... m1 = HGBR(max_iter=20).fit(X[treated], Y[treated]) ... m0 = HGBR(max_iter=20).fit(X[~treated], Y[~treated]) ... return (m1, m0) >>> def cate_fn(state, X): ... m1, m0 = state ... return m1.predict(X) - m0.predict(X) >>> methods = [ ... GenericCATEAdapter(fit_linear, cate_fn, name="linear"), ... GenericCATEAdapter(fit_hgb, cate_fn, name="hgb"), ... ] >>> ens = CausalEnsemble(methods=methods, aggregation=RStacking()) >>> _ = ens.fit(X, T, Y, random_state=42) >>> ens.ate() AteEstimate(ate=..., n_methods=2, aggregation='RStacking', spread=...)
Methods
__init__aggregateAggregate component CATEs using stored weights.
Compute R-Stacking weights from OOF predictions and nuisance estimates.
Attributes
ensemble_weightsEnsemble weights computed during
fit().fit_nuisance_fnoutcome_modelpropensity_modelpropensity_trimstrategy_familysplitDetails
- fit_weights(cate_predictions, Y, T, X, nuisance)[source]¶
Compute R-Stacking weights from OOF predictions and nuisance estimates.
- Parameters:
cate_predictions (array of shape (K, m)) – Out-of-fold CATE predictions; one row per component model.
Y (arrays of shape (m,)) – Observed outcome and treatment for the m OOF/averaging observations.
T (arrays of shape (m,)) – Observed outcome and treatment for the m OOF/averaging observations.
X (array of shape (m, p)) – Covariates (not used directly; included for interface consistency).
nuisance (NuisanceEstimates) – Out-of-fold nuisance predictions for the same m observations. Uses
nuisance.m_hatandnuisance.e_hatfor Robinson residuals.
- Returns:
EnsembleWeights with
weights = α̂(shape K, non-negative) andintercept = ĉ. Model names are populated by_fit_supervised.
- Return type: