Supported estimands#
A discrete point treatment and the mean group: every treatment-specific mean and the
reference-arm contrasts requested through ey and ate. For multiple levels, the
univariate implementation follows R drtmle’s armwise construction (R/fluctuate.R, fluctuateG):
reduced regressions and the two extra equations are fitted once per arm, and equation (9)
independently fluctuates each one-vs-rest mechanism margin with response 1(A = a), offset
logit(g_a), covariate Qr_a / g_a, one scalar per arm.
The targeted margins are not renormalised, and the reason is that what this estimator
owes is a set of solved score equations rather than a likelihood: projecting the K tilted
margins back onto the simplex would move every one of them off the root just found. They
are not inert, and the estimate does see them: the next round’s equation (8) divides by g_a*,
so the targeted Qbar* and hence psi do depend on margins that sum to something other than
one (measured: 0.9975 on the three-armed fixture). That is what drtmle does too, and it is
licensed by the score equations rather than by the mechanism still being a conditional
distribution. The initial categorical mechanism is compatible and sums to one, using
cleverly’s existing multiclass learner path; diagnostics.support() reports how far the
targeted rows depart from it.
Two arms keep their own route, which is not the armwise one. drtmle fluctuates both
margins independently even at K = 2; cleverly instead tilts g_1 alone along a
two-column covariate, so g_0* = 1 - g_1* holds exactly. Both solve the same two score
equations. Column 0’s is P_n[Qr_0/g_0* {1(A=a_0) - g_0*}] = 0 once the sign convention in
reduced_mechanism_covariate is unwound. They differ only in the submodel. No read source
states that this difference is second order, so that statement is an unsourced derivation.
Because the two-arm route differs from the armwise one, the estimator is not continuous in K,
and a reader comparing a two-arm
cleverly fit against a two-arm drtmle fit should expect agreement in the equations solved
rather than in the iterates.
RM19 measured the two routes on 2,000 fresh draws of the binary treatment_correct law at
n = 3000. There, the treatment mechanism is correct and the outcome regression is not. The
transcription of the R loop took each of four named choices from R or from this package.
Averaged over the other three choices, the two-arm tilt raised the mean ate by 0.000833 to
0.001718, at the level 0.998. The whole difference from R reads no increment at the declared resolution.
sqrt(n) times that difference falls from 0.0789 at n = 1500 to 0.0053 at
n = 6000. Three sizes do not prove a rate, and that measurement does not isolate the tilt.
What the localization design found gives each
interval.
from sklearn.linear_model import LinearRegression, LogisticRegression
from cleverly import ATE, CausalStudy, DRTMLEMethod, PointTreatment
from cleverly.datasets import make_nonlinear_ate
frame, truth = make_nonlinear_ate(n=1000, seed=0)
study = CausalStudy(
frame,
design=PointTreatment(
outcome="Y",
treatment="A",
adjustment=("W1", "W2", "W3", "W4"),
),
)
res = study.estimate(
ATE(),
method=DRTMLEMethod(guard=("Q", "g")),
outcome_learner=LinearRegression(),
treatment_learner=LogisticRegression(max_iter=1000),
cross_fit=False,
random_state=0,
)
make_nonlinear_ate has a Gaussian outcome, whose support is the whole real line, so this fit
turns cross-fitting off. A cross-fitted fit of a continuous outcome is refused unless q_bounds
declares the support. DRTMLE inherits that refusal from TMLE. The
fold and outcome-scale rules give the message.
guard= says which extra equations to solve, in drtmle’s vocabulary and crossed the way that
package crosses it. Both apply by default. It also names the corrections the reported curve
subtracts: one per equation solved, so guard=("g",) reports D = D* − D*_Q and the score
check’s verdict names that curve. The other equation’s correction is still recomputed and
reported, held to no threshold, because it is what says what the guard did not buy. An empty
guard is a plain TMLE, bit for bit.
Supported, with conditions#
keyword |
status |
|---|---|
a declared known mechanism |
complete data at every |
|
|
|
without |
|
a declared missing treatment, with or without |
|
fixed analysis weights only. The estimand is the parameter of the tilted law |
|
supported; varies exactly one thing, the primary split. Each draw fits its own reductions and runs its own alternation; the report uses the median point and split-adjusted median variance. |
|
supported for complete outcomes and discrete treatment. It fits one reduced probability on the two-column `(Qbar-hat(a,W), g-hat(a |
a random-forest reduction learner |
computes, but steps outside the cross-fitting argument of section 3, because its fitted class grows with |
|
permitted, and it puts the fit outside the asymptotic half of the bound-inactive scope: the argument needs a bound sequence going to zero, which |
|
required with |
|
|
What the composite indicator accepts. The composite construction takes every composition
that both of its parents take. Each row has evidence in tests/unit/test_composite_missing_data.py.
composition |
composite TMLE ( |
composite DR-TMLE (non-empty |
|---|---|---|
|
|
|
|
not applicable |
|
|
yes |
yes; |
|
yes |
yes |
|
yes, in one pooled outcome step |
yes; see baseline strata |
|
yes; a replicate resamples rows with their |
yes |
|
yes, screened on the recorded rows |
yes |
|
not applicable |
refused: both constructions carry one fold-free treatment mechanism, and the composite has up to three factors |
|
yes; the covariate is the arm covariate at the arm the rule assigns |
refused, as on complete data |
|
yes; each coefficient projects the identified arm means |
refused, as on complete data |
|
refused (F21) |
refused |
The fit is in sample, cross_fit=False. Each nuisance factor is fitted on the rows it conditions on.
The missingness_learner fits both observation factors. R drtmle 1.1.2 fits the treatment
observation factor with its one treatment learner, SL_g.
What delta= accepts on the randomized route. Set randomized=True to estimate the treatment
probabilities. You can instead declare the known probabilities on the data with
treatment_probabilities= in fit or in CausalData.from_frame. The probabilities can depend on
W, as in a stratified randomization. The
point-treatment contract gives the
accepted forms. Prefer a mapping of each level to its frame column, such as
{"placebo": "p_placebo", "active": "p_active"}. The positional forms bind to arm codes, which
are indices into the sorted levels.
The randomized surface requires cross_fit=False, repeats=1, pooled reductions, and no analysis
weights or evaluation companion.
With guard=(), the same declaration configures a plain TMLE at the design mechanism. The result is
the ordinary estimator bit for bit, which is what a pure randomization-probability analysis wants.
The other conditions above then do not apply, because no extra equation is solved and no theorem is
claimed. cross_fit=False still applies. DRTMLE refuses delta= with cross_fit=True at every
guard, including guard=(), before any learner is fitted
(tests/unit/test_drtmle_missing.py::test_an_unguarded_cross_fitted_missing_outcome_fit_is_refused).
Ordinary TMLE admits a cross-fitted missing-outcome fit only under its
stacked contract.
Why weights= transports. The derivation was read at an unweighted law. Transporting it needs
two things at once. The reduced regressions must be P_w-conditional expectations, which weighted
loss gives. The mechanism they condition on and divide by must be the P_w mechanism, which holds
because they are built from nuisance.propensity. tests/unit/test_remainder_drtmle.py runs the
whole expansion at two tilted laws, and keeps the wrong transport as a control that fails.
tests/unit/test_simulated_confounding.py adds the applied evidence. It refits nonuniform-weight
complete-outcome fits for each binary parameter DR-TMLE can replay: the arm means, the ATE, the
risk ratio, and the odds ratio. The identified effect’s method catalog refuses PAR and PAF under
DR-TMLE, so that test replays neither. The test also removes the weight from the reduced
regressions alone, and requires the cell estimate to move. Neither file establishes interval
validity or weighted parity with the canonical implementation.
Baseline strata#
A fit with strata= reports each stratum’s DR-TMLE beside the marginal one, at every guard and
on every route: complete data, the randomized missing-outcome construction, and the composite
indicator. The table gives what changes inside the alternation.
piece |
stratified form |
|---|---|
equations (8), (9) and (10), and the missing-outcome tilts |
one block \(I(S=s) H / P_n(S=s)\) per stratum for each covariate |
reduced regressions |
fitted inside each stratum, on the stratum’s rows of each fold’s training complement |
evaluation companion ( |
each companion row moves by its own stratum’s coefficients |
Each stratum’s equations then share no row with another stratum’s, so a stratum’s estimate is
the DR-TMLE of the law given \(S=s\). tests/unit/test_stratified_drtmle_exact.py checks this
against separate fits on the stratum subsets, on every route. The
stratified DR-TMLE study measures the marginal and
stratum ATEs against exact truths and pairs the stratum targets with R drtmle.
The marginal estimate is the \(P_n(S=s)\)-weighted mixture of the stratum estimates. Its reductions condition on \((g_n(W), S)\), which is finer than the \(g_n(W)\) of Theorem 1 of Benkeser et al. (2017).
The theorem’s iterated-expectation step needs only that the weights in (9) and (10) are measurable in the conditioning sigma-field. Its rate conditions hold inside each stratum for a fixed number of strata. The marginal estimate is therefore valid under Theorem 1’s conditions in each stratum, and it differs from the estimate of an unstratified fit. The one-wrong limits of the conditioning terms apply per stratum. The arm targets of ordinary TMLE follow the same convention.
A stratum with no trainable row of some arm in some fold’s training complement refuses after the fold draw and before any learner.
Refused by name#
Each row below is refused because the derivation read here does not cover it, or because no code
path accepts the input. A refused row raises at construction or at fit. Its message names what a
derivation would need. An undeclared missing treatment raises DataError from the data container,
and its message names treatment_delta=. Every refusal of a declared missing treatment comes from
one gate before any learner, and tests/unit/test_refusals_before_the_nuisance_fit.py pins each
one.
The weights_estimated= row does not raise. The fit runs and reports its point estimate under the
"estimated_weight_plugin" status when its weights vary. Constant weights fit the unweighted
estimator, so a constant column declared estimated keeps its interval. Its ci, pvalue, and
std_error raise CapabilityError, and plugin_std_error and plugin_interval report the
retained diagnostic.
refused |
why |
|---|---|
continuous treatment |
the reductions and corrections are indexed by treatment mass at a discrete arm; a continuous dose requires density-based equations. See F5 |
|
the supported missing-outcome estimator is Díaz & van der Laan’s distinct five-reduction construction, not the complete-outcome one- versus two-dimensional choice. |
|
a different score equation with no reduced-dimension derivation |
|
as above. X50 holds |
an undeclared missing treatment value |
the package does not infer a missing treatment from a missing value. The data container raises |
a missing treatment with |
when the recording may depend on the treatment, |
a missing treatment with |
the composite conditions identify the value of a fixed rule. No composite derivation for a rule learned from the fit is written, and the value is cross-fitted. See F27 |
a missing treatment with |
no derivation of the composite indicator for a controlled direct effect is written, and the condition that ties |
a missing treatment with |
it selects Díaz & van der Laan’s construction, which observes the treatment on every row |
a missing treatment with a declared known mechanism |
a missing treatment needs |
|
the companion’s mechanism must be its own declaration. Declare the same columns on the companion |
a missing treatment with a C-TMLE selector strategy or the shared outcome-adaptive design |
no collaborative score is derived for the composite indicator. X51 part (d) holds the selector point estimate, and F19 the shared design. The per-arm outcome-adaptive |
|
the reduced equations carry no controlled-intermediate factor |
|
the published missing-outcome theorems use Donsker conditions and do not establish a cross-validated extension. With |
|
each fold would need its own reduced regressions and alternation. See F5 |
|
the common-update construction would need the corrected parameter and influence curve derived under fold-wise evaluation. See F5 |
composition with |
a reduced regression conditions on |
estimated weights ( |
fits, and reports the |
|
each by name; the middle one on cost, up to 20,000 adaptive steps |
|
on cost, as the |
|
there is no complement to leave a fold out of; nested leaves two folds out at a time. |
a continuous outcome with |
the scale would come from every observed outcome, held-out rows included, and no shipped result covers it. See the fold and outcome-scale rules |
|
the partition would be a function of the data the fit then conditions on. Refused when the declaration is constructed |