causalis.scenarios.uplift.policy¶
Interpretable treatment decisions learned from cross-fitted IRM signals.
Module Contents¶
Classes¶
Independent evaluation of a frozen policy, in outcome units. |
|
Learn a shallow, greedy treatment policy from a fitted IRM. |
API¶
- class causalis.scenarios.uplift.policy.UpliftPolicyEvaluation¶
Independent evaluation of a frozen policy, in outcome units.
Let :math:
\widehat\pi(Z)\in\{0,1\}be a policy learned on training clients, where :math:Zcontains the policy features. On independent evaluation clients,summary()estimates policy gains andrules_summary()estimates effects within each fixed leaf.The causal policy value is
.. math::
V(\pi) = \mathbb{E}\!\left[ \pi(Z)Y(1) + (1-\pi(Z))Y(0)\right].Reports contain differences in this value, not the absolute expected outcome. Higher outcomes are better; no treatment cost is subtracted.
Attributes
diagnostics : dict Training and evaluation overlap settings, clipping counts and fractions, sample sizes, and inference conventions. Clipping can introduce bias. alpha : float Significance level; intervals have nominal coverage :math:
1-\alpha.Notes
Approximate inference assumes unconfoundedness, adequate overlap, suitable nuisance estimation, and independent observations. Rule intervals are pointwise HC3 intervals, not individual-effect or simultaneous intervals. Evaluation conditions on the learned policy; it does not quantify variation from retraining or justify tuning the policy using evaluation results.
- diagnostics: dict[str, Any]¶
None
- alpha: float¶
None
- summary() pandas.DataFrame¶
Return policy gains, standard errors, intervals, and targeting share.
On the evaluation sample of size :math:
n, let :math:a_i=\widehat\pi(Z_i)and let :math:\Gamma_ibe the cross-fitted doubly robust signal defined in :class:UpliftPolicyTree. Each comparison uses a paired per-client signal:.. math::
S_i^{\mathrm{policy\_vs\_none}} &= a_i\Gamma_i, \\ S_i^{\mathrm{policy\_vs\_all}} &= (a_i-1)\Gamma_i, \\ S_i^{\mathrm{all\_vs\_none}} &= \Gamma_i.For each signal :math:
S_i, the reported estimate and standard error are.. math::
\widehat\Delta = \overline S = \frac{1}{n}\sum_{i=1}^n S_i, \qquad \widehat{\mathrm{SE}}(\widehat\Delta) = \sqrt{\frac{\sum_{i=1}^n(S_i-\overline S)^2}{n(n-1)}}.The approximate normal interval is
.. math::
\widehat\Delta \;\pm\; \Phi^{-1}(1-\alpha/2)\widehat{\mathrm{SE}}(\widehat\Delta).Returns
pandas.DataFrame A copy with one row per
comparison.valueis the average gain per evaluation client, including clients the policy does not treat; it is not the average among targeted clients alone.std_error,ci_lower, andci_upperdescribe that gain.n_obsis the full evaluation size.treatment_fractionis :math:n^{-1}\sum_i a_i, the learned policy’s targeting share in every row, not the historical treatment rate or the baseline share.Notes
Positive
policy_vs_allfavors the policy over treating everybody; negative values favor treating everybody. An interval crossing zero does not establish the direction of the gain.
- rules_summary() pandas.DataFrame¶
Return effects and support for every frozen rule.
A leaf :math:
\elldefines a region :math:R_\ellby the conjunction of its predicates. Its evaluation clients are :math:I_\ell=\{i:Z_i\in R_\ell\}, with :math:n_\ell=|I_\ell|. The target is the group average treatment effect.. math::
\tau_\ell = \mathbb{E}[Y(1)-Y(0)\mid Z\in R_\ell], \qquad \widehat\tau_\ell = \frac{1}{n_\ell} \sum_{i\in I_\ell}\Gamma_i.For a supported leaf, HC3 inference for the saturated group regression gives
.. math::
\widehat{\mathrm{SE}}_{\mathrm{HC3}}(\widehat\tau_\ell) = \sqrt{\frac{\sum_{i\in I_\ell} (\Gamma_i-\widehat\tau_\ell)^2}{(n_\ell-1)^2}}, \qquad \mathrm{CI}_\ell = \widehat\tau_\ell \;\pm\; \Phi^{-1}(1-\alpha/2) \widehat{\mathrm{SE}}_{\mathrm{HC3}}(\widehat\tau_\ell).Returns
pandas.DataFrame A copy with one row per training leaf, including leaves with no evaluation clients. Columns are:
* ``rule_id``: stable identifier of the learned leaf. * ``conditions``: readable conjunction defining its region. * ``predicates``: exact ``(feature, operator, threshold)`` tuples. * ``action``: training decision :math:`a_\ell`, either 1 (target) or 0 (do not target); evaluation never changes it. * ``n_eval``: :math:`n_\ell`. * ``n_treated``: :math:`\sum_{i\in I_\ell}D_i`. * ``n_control``: :math:`\sum_{i\in I_\ell}(1-D_i)`. * ``status``: ``ok`` when both historical arms are present, ``empty`` when :math:`n_\ell=0`, or ``insufficient_arm_support`` when one historical arm is absent. ``ok`` is a support check, not proof of reliable causal estimation. * ``value``: :math:`\widehat\tau_\ell`, irrespective of the action. * ``std_error``: the HC3 standard error above. * ``ci_lower``, ``ci_upper``: endpoints of the pointwise interval.Notes
Unsupported and empty leaves have NaN effect estimates and intervals. Their clients remain in the overall policy evaluation. A positive
valuemeans estimated benefit from treatment even ifactionis 0. An interval entirely above/below zero supplies evidence of positive/negative group uplift; an interval crossing zero leaves its direction unresolved. These intervals describe group means, not effects for individual clients. Disagreement with the training action is evidence to review the policy, not an automatic update to it.
- class causalis.scenarios.uplift.policy.UpliftPolicyTree(*, max_depth: int = 2, min_samples_leaf: int = 50, min_samples_per_arm: int = 5)¶
Bases:
sklearn.base.BaseEstimatorLearn a shallow, greedy treatment policy from a fitted IRM.
Let :math:
D\in\{0,1\}denote historical treatment, :math:Ythe observed outcome, :math:Xall pre-treatment adjustment variables, and :math:Zthe subset allowed in policy rules. Under consistency, unconfoundedness :math:(Y(0),Y(1))\perp D\mid X, and overlap :math:0<e(X)=P(D=1\mid X)<1, the CATE is.. math::
\tau(x)=\mathbb{E}[Y(1)-Y(0)\mid X=x] =g_1(x)-g_0(x), \qquad g_d(x)=\mathbb{E}[Y\mid X=x,D=d].Using out-of-fold nuisance predictions, construct the doubly robust signal
.. math::
\Gamma_i = \widehat g_1^{(-k(i))}(X_i) -\widehat g_0^{(-k(i))}(X_i) +\frac{D_i\{Y_i-\widehat g_1^{(-k(i))}(X_i)\}} {\widetilde e_i} -\frac{(1-D_i)\{Y_i-\widehat g_0^{(-k(i))}(X_i)\}} {1-\widetilde e_i},where :math:
k(i)is the fold containing observation :math:iand :math:\widetilde e_i=\min(1-\epsilon, \max(\epsilon,\widehat e^{(-k(i))}(X_i)))is IRM’s clipped propensity. Clipping stabilizes denominators but can bias the signal; double robustness does not remove hidden confounding or guarantee validity under clipping.The empirical policy objective, relative to treating nobody, is
.. math::
\widehat J(\pi)=\frac{1}{n_{\mathrm{train}}} \sum_{i\in\mathcal T}\pi(Z_i)\Gamma_i.The tree greedily improves this objective. It does not solve a global optimization over all possible trees; see :meth:
fitfor the split reward.Parameters
max_depth : int, default 2 Maximum number of splits along a path; zero learns a constant policy. min_samples_leaf : int, default 50 Minimum observations in each child of an accepted split. min_samples_per_arm : int, default 5 Minimum treated and control observations in each child.
Notes
A leaf treats when its training mean signal is positive. Greedy search can miss interactions needing a zero-gain first split. If no split is feasible, a constant root policy is retained even when the sample is smaller than the child-size limits.
All adjustment variables belong in IRM;
policy_featuresonly limits the rules. Features must be numeric, finite, and measured before intervention. Higher outcomes are better; costs, capacity constraints, weighted samples, and overlap-based sample dropping are not supported. Decisions estimate group benefit, not whether each individual will benefit.Split clients before fitting either IRM or tuning the policy. Evaluation checks disjoint IDs but cannot verify the provenance of nuisance learners or prevent reuse of evaluation results for tuning.
Initialization
- fit(train_irm: causalis.scenarios.unconfoundedness.model.IRM, *, policy_features: Sequence[str] | None = None)¶
Discover rules using only the training IRM’s cross-fitted signals.
For a node containing training indices :math:
A, the optimal constant action and its unnormalized reward are.. math::
a_A = \mathbf{1}\!\left\{\sum_{i\in A}\Gamma_i>0\right\}, \qquad W(A)=\max\!\left(0,\sum_{i\in A}\Gamma_i\right).A candidate feature/threshold pair partitions :math:
Ainto :math:L=\{i\in A:Z_{ij}\le t\}and :math:R=\{i\in A:Z_{ij}>t\}. Its gain is.. math::
G(j,t;A)=W(L)+W(R)-W(A).
Accept the feasible split with greatest positive gain, allowing for floating-point roundoff. Both children must satisfy the total and per-arm sample limits. Recurse until no improvement is available or
max_depthis reached. Feature order and then ascending thresholds break ties. A zero leaf signal recommends no treatment.Parameters
train_irm : IRM Fitted, unweighted IRM with ``overlap_policy=’clip’` and unchanged CausalData containing unique, nonmissing client IDs. policy_features : sequence of str, optional Ordered, nonempty subset of fitted confounders allowed in the rules. Defaults to all confounders. Other confounders still enter the nuisance models and the DR signal.
Returns
UpliftPolicyTree The fitted policy. No IRM models are fitted or modified.
Notes
Signals are computed from fitted nuisances, independently of the last requested IRM estimand (including ATTE) and any lazy CATE scoring models.
- rules() pandas.DataFrame¶
Return the learned rules and descriptive training statistics.
For training clients :math:
\mathcal T_\ellin leaf :math:\ell,.. math::
\overline\Gamma_{\ell,\mathrm{train}} =\frac{1}{|\mathcal T_\ell|} \sum_{i\in\mathcal T_\ell}\Gamma_i, \qquad a_\ell=\mathbf{1}\{ \overline\Gamma_{\ell,\mathrm{train}}>0\}.Returns
pandas.DataFrame A copy containing
rule_id, readableconditions, exactpredicatestuples(feature, operator, threshold),action(:math:a_\ell),n_train,n_treated_train,n_control_train, andtrain_mean_uplift_descriptive(:math:\overline\Gamma_{\ell,\mathrm{train}}). All predicates along a path must hold; the leaves form a disjoint partition.Notes
Training means are selected on the same data used to discover the rules and carry no independent confidence intervals. Use :meth:
evaluateand :meth:UpliftPolicyEvaluation.rules_summaryfor held-out evidence.
- assign(clients: pandas.DataFrame, *, user_id: str) pandas.DataFrame¶
Assign clients without outcomes or historical treatment labels.
For disjoint learned regions :math:
R_\elland frozen leaf actions :math:a_\ell, the assignment function is.. math::
\widehat\pi(z)=\sum_{\ell=1}^K a_\ell\mathbf{1}\{z\in R_\ell\}.Each client belongs to exactly one leaf. A threshold test sends :math:
z_j\le tleft and :math:z_j>tright, including equality on the left. Neither outcomes nor estimated individual effects enter this assignment step.Parameters
clients : pandas.DataFrame Client IDs and the fitted policy feature columns. Features must be numeric, finite, and nonmissing. Extra columns are ignored. user_id : str Column containing unique, nonmissing IDs. Cannot be
rule_idoraction, which are reserved output column names.Returns
pandas.DataFrame Original ID column plus
rule_idand integeraction: 1 means target, 0 means do not target. Input order, ID dtype, and index are preserved. Empty inputs return the same output schema.
- evaluate(eval_irm: causalis.scenarios.unconfoundedness.model.IRM, *, alpha: float = 0.05) causalis.scenarios.uplift.policy.UpliftPolicyEvaluation¶
Evaluate frozen decisions on an IRM fitted on disjoint clients.
For an independent evaluation population and a fixed learned policy, the estimands are
.. math::
\Delta_{\pi,0} &= V(\widehat\pi)-V(0) =\mathbb{E}[\widehat\pi(Z)\tau(X)], \\ \Delta_{\pi,1} &= V(\widehat\pi)-V(1) =\mathbb{E}[(\widehat\pi(Z)-1)\tau(X)], \\ \Delta_{1,0} &= V(1)-V(0)=\mathbb{E}[\tau(X)].Estimate them with evaluation-only cross-fitted DR signals. See :meth:
UpliftPolicyEvaluation.summaryfor paired-signal standard errors and :meth:UpliftPolicyEvaluation.rules_summaryfor leaf HC3 intervals.Parameters
eval_irm : IRM Independently fitted, unweighted IRM with
overlap_policy='clip'. Outcome, treatment, and ordered confounder definitions must match training. Its original CausalData and IDs must remain unchanged, and its IDs must be disjoint from training IDs. alpha : float, default 0.05 Significance level in :math:(0,1)for nominal :math:100(1-\alpha)\%intervals.Returns
UpliftPolicyEvaluation Overall policy gains, per-rule effects and support, and overlap diagnostics. The policy, training summaries, and both IRMs are left unchanged.
Notes
Unsupported leaves have unavailable subgroup estimates; their clients remain in the overall policy evaluation, whose inference relies on population overlap. An interval crossing zero does not establish a zero effect, and evaluation never changes a learned action. If these results are used to revise or select policies, evaluate the selected policy on another untouched sample.