cleverly.interventions.IPSISet#

class cleverly.interventions.IPSISet(names: tuple[str, ...], factors: tuple[tuple[float, ...], ...], values: ndarray[tuple[Any, ...], dtype[float64]], weights: ndarray[tuple[Any, ...], dtype[float64]], normaliser: ndarray[tuple[Any, ...], dtype[float64]], propensity: ndarray[tuple[Any, ...], dtype[float64]], reference: float = 0.0, mechanism_known: bool = False)[source]#

Every declared tilt, evaluated against the estimated mechanism.

Holds arrays and no callables, for the reason RegimeSet and PolicySet do: a fit reached through retarget() – the bootstrap, a result loaded from disk – targets the same declared tilts without the mechanism being refit.

Parameters:
namestuple of str

One per tilt, in declaration order. Report labels.

factorstuple of tuple of float

One (K,) tuple per tilt, in declaration order and arm-code order: the resolved factor \(\delta_{r,a}\) of every level. Not the keys of the per-parameter arrays: those are the codes 0.0 .. R-1.0, exactly as PolicySet keys by ordinal rather than by factor.

valuesndarray

(n, K, R), \(q_{\delta_r}(a \mid W_i)\) – the tilted density, columns in arm-code order. Rows sum to one by construction.

weightsndarray

(n, K, R), \(h_{\delta_r}(a, W_i) = q_{\delta_r}(a \mid W_i) / g(a \mid W_i)\) – the clever covariate arm by arm. Computed in the cancelled form \(\delta_a / D\) rather than as a ratio, so it never divides by a small mechanism; see the module docstring.

normaliserndarray

(n, R), \(D_{\delta_r}(W_i) = \sum_b \delta_{r,b}\, g(b \mid W_i)\). On two levels it is computed in Kennedy’s form \(\delta g_1 + g_0\) with \(\delta = \delta_1/\delta_0\), which is \(D\) divided by \(\delta_0\). The tilt is scale free, so \(q\) and \(h\) do not depend on that choice.

propensityndarray

(n, K), the \(g(a \mid W)\) these arrays were built from, untruncated. Carried because both the influence curve’s mechanism term and the mechanism fluctuation’s offset need it, and because an IPSISet recomputed at a fluctuated mechanism must be able to say which one it describes.

referencefloat

Code of the tilt contrasts are taken against.

mechanism_knownbool

Whether propensity is a declared known mechanism (known_treatment) rather than an estimate. Then \(q_\delta(g_0)\) is a known stochastic regime: the model has no mechanism scores, so the targeting step solves no mechanism equation and the influence curve has no mechanism term. That curve is the curve of the Stochastic regime at the same density (Kennedy 2019, the incremental curve projected off the mechanism tangent space).

Methods#

IPSISet.at(propensity: ndarray[tuple[Any, ...], dtype[float64]]) → IPSISet[source]#

The same tilts recomputed at a different (n, K) mechanism.

What the mechanism fluctuation calls after each update. The declared tilts are unchanged – a tilt is a statement about odds, not about a particular \(g\) – so only the evaluated arrays move.

Parameters:
propensityndarray

(n, K) mechanism \(g(a \mid W)\) to recompute the tilts at.

Returns:
IPSISet

The same declared tilts, evaluated at the new mechanism.

classmethod IPSISet.evaluate(incrementals: Sequence[Incremental], data: CausalData, propensity: ndarray[tuple[Any, ...], dtype[float64]], *, reference: str | None = None) → IPSISet[source]#

Evaluate every tilt against an (n, K) mechanism, columns in arm-code order.

propensity is the untruncated out-of-fold mechanism. Truncating it would move the parameter rather than the estimator, since \(g\) appears in \(\Psi(\delta)\) itself, and no truncation is needed: nothing here divides by \(g\). build_submodel() therefore hands the ipsi builder a bounded mechanism which that builder discards, reading these arrays instead.

Parameters:
incrementalssequence of Incremental

The tilts to evaluate, in the order their codes will follow.

dataCausalData

Validated study data, which supplies the arm order and the labels.

propensityndarray

(n, K) estimated mechanism, columns in arm-code order, untruncated.

referencestr or None

Label of the tilt contrasts are taken against. None uses the first.

Returns:
IPSISet

Every tilt evaluated against that mechanism.

IPSISet.label(code: float) → str[source]#

Return the label for one indexed policy.

Parameters:
codefloat

Tilt code.

Returns:
str

The label the tilt was declared under.

IPSISet.observed(treatment: ndarray[tuple[Any, ...], dtype[float64]]) → ndarray[tuple[Any, ...], dtype[float64]][source]#

(n, R) – the clever covariate at the arm each unit actually received.

Parameters:
treatmentndarray

(n,) observed treatment, in arm codes.

Returns:
ndarray

(n, R) clever covariate at the arm each unit actually received.

IPSISet.subset(index: Any) → IPSISet[source]#

The same tilts on a row subset – a fold, a bootstrap resample.

Sliced rather than re-evaluated, for the reason subset() gives: re-deriving the tilt on a resample would let the resample redefine the estimand.

Parameters:
indexarray_like

Row positions or a boolean mask.

Returns:
IPSISet

The same tilts over the selected rows.

Attributes#

IPSISet.binary_derivative#

(n, R) – \(\delta_r / D_{\delta_r}^2\) for a treatment with two levels.

The factor that multiplies \(\{\bar Q(1, W) - \bar Q(0, W)\}(A - g)\) in the binary influence curve, with \(\delta_r = \delta_{r,1}/\delta_{r,0}\). The three-level and larger forms read weights instead.

Returns:
ndarray

(n, R) factor for each tilt.

Raises:
ValueError

If the treatment does not have two levels.

IPSISet.codes#

The keys the per-parameter arrays use, (0.0, ..., R-1.0).

IPSISet.labels#

Code to reported label, which is what parameter_name is given.

IPSISet.mechanism_known: bool = False#
IPSISet.n#

Return the number of observations.

IPSISet.n_arms#

Return the number of treatment arms.

IPSISet.n_tilts#

Return the number of incremental interventions.

IPSISet.reference: float = 0.0#
IPSISet.names: tuple[str, ...]#
IPSISet.factors: tuple[tuple[float, ...], ...]#
IPSISet.values: ndarray[tuple[Any, ...], dtype[float64]]#
IPSISet.weights: ndarray[tuple[Any, ...], dtype[float64]]#
IPSISet.normaliser: ndarray[tuple[Any, ...], dtype[float64]]#
IPSISet.propensity: ndarray[tuple[Any, ...], dtype[float64]]#