cleverly 0.1.2#

This alpha release extends missing-data, treatment-policy, and longitudinal analyses, with APIs for known treatment and censoring mechanisms. It also changes cross-fitting defaults and makes inference restrictions explicit. These are the changes since 0.1.1.

Upgrade notes#

Review these API changes before refitting an analysis under 0.1.2.

Replace shifts= with policies= in TMLE, ModifiedTreatmentPolicy, and ModifiedTreatmentPolicyEffect. Replace ey_shift and ate_shift with ey_policy and ate_policy. ShiftSet, ShiftSupport, and check_shift_support become PolicySet, PolicySupport, and check_policy_support. Import Shift from cleverly.interventions. (#269)

Cross-fitting now draws unstratified outer folds by default. Treatment-based and outcome-based fold strata are refused. For continuous outcomes, declare known outcome bounds with Targeting(q_bounds=(lower, upper)). Do not calculate these bounds from the observed sample. Use CrossFitting(enabled=False) for an in-sample fit. (#218)

Declare supplied rules, intervention densities, MSM designs, and projection weights as known when they are fixed independently of the analysis sample. The relevant arguments are rule_kind, density_kind, design_kind, and weights_kind. Undeclared or estimated functions are refused on these paths. (#224, #225, #227, #228)

Check each estimate’s supplies_inference before reading uncertainty estimates. C-TMLE selection paths and some estimated-weight DR-TMLE fits withhold standard errors, confidence intervals, and p-values. Their plugin_std_error and plugin_interval remain available as diagnostics. (#223, #224)

Move DRTMLEMethod(treatment_probabilities=...) declarations to PointTreatment(treatment_probabilities=...). Study designs accept mappings from treatment levels to probability columns. Pass arrays through the estimator’s fit method instead. (#276)

Replace diagnostics.stagewise() with diagnostics.support() and cv_targeting.fold_evaluated with cv_targeting.canonical. The loader does not migrate saved results. Loading a result from another version emits VersionMismatchWarning and may fail. Refit analyses under 0.1.2 when migrating saved results. (#236)

Added#

Study protocols and reusable splits#

Studies can record their scientific protocol and reuse the outer folds from a previous fit. StudyProtocol records the population, eligibility, treatment strategies, outcome, follow-up, and assumptions. Identification retains the record, and fitted provenance carries its digest. (#201)

SplitPlan records assignments across cross-fitting repeats. Pass result.split_plan through CrossFitting(split_plan=...) to reuse them. Fits require package-generated assignments and validate the plan before fitting learners. (#202, #218)

Missing data and baseline strata#

Additional estimands support missing outcomes, missing treatments, and estimates within baseline strata.

NaturalCourseMean estimates the population outcome mean with outcomes missing at random. Ordinary TMLE and the supported stacked cross-fitted configuration are available. (#207, #210)

Stacked CV-TMLE supports arm means and contrasts with missing outcomes, subject to its fold, scale, and composition restrictions. (#216)

Missing-outcome DR-TMLE supports randomized treatments with three or more arms. Known treatment probabilities can be supplied by arm. (#260)

TMLE and DR-TMLE support a declared missing treatment, with or without missing outcomes, through a composite observation indicator. Use treatment_delta= on the estimator or treatment_missingness= on PointTreatment. Cross-fitting remains unsupported for this construction. (#261)

Ordinary TMLE estimates population attributable risk and fraction with outcomes missing at random. The stacked cross-fitted route requires a binary outcome and excludes weights and clusters. (#262)

Baseline-stratum targeting extends to incremental interventions, MSMs, natural-course means, and DR-TMLE. Fold-local targeting and fold evaluation remain unsupported with strata. (#263)

Known treatment and censoring mechanisms#

Fits can use treatment probabilities declared by a randomized design instead of estimating them. TMLE.fit(treatment_probabilities=...) and PointTreatment(treatment_probabilities=...) accept known treatment probabilities. TMLE and DR-TMLE use the declaration without fitting a treatment learner. (#276)

LTMLE accepts known treatment and censoring probabilities at individual nodes, including survival and time-to-event designs. Declare them with treatment_probabilities= and censoring_probabilities=; nodes without declarations still estimate their mechanisms. The fit refuses a regimen that requires an event with declared probability zero. (#276)

Known treatment probabilities replace only the treatment mechanism. Missing-outcome and controlled-direct-effect fits still estimate their additional mechanisms and retain their inference conditions. (#276)

Treatment policies and learned rules#

Policy estimation now covers additional dose transformations and categorical policies.

Modified treatment policies include scaling, piecewise transformations, custom invertible maps, categorical maps, and randomizers with known probabilities. They run through point-treatment TMLE and supported longitudinal nodes. (#269)

ratio="classifier" estimates a policy density ratio by classification. RiskRatioTilt provides a separate binary-treatment policy through the estimator API. (#269)

LearnedRuleValue estimates the average value of binary treatment rules learned separately within the training folds. It requires cross-fitting and fold evaluation. Its target is the fold-average learned-rule value, rather than the value of an optimal rule or one fitted on all rows. (#248, #249)

Longitudinal regimen nodes accept known stochastic categorical policies through Stochastic(..., density_kind="known"). (#268)

Longitudinal and survival analyses#

Longitudinal estimation adds baseline-treatment survival input, clustered cross-fitting, and derived summaries.

TimeToEvent and LongitudinalData.from_time_to_event() accept one follow-up time and event code per unit. They support a baseline treatment held over the survival nodes. Censoring between declared grid times is refused. (#270)

Clustered LTMLE cross-fits with whole clusters assigned to folds. Longitudinal MSMs also cross-fit, with one pooled targeting update per node. LTMLE(msm=...) now runs with the default ten folds. (#265, #266)

ratio() derives risk ratios or odds ratios from fitted parameters. wald_test(null=...) tests a specified null, and Transform supports transformed confidence intervals. (#258)

rmst() and rmtl() report restricted mean survival time and time lost, including between-regimen contrasts. Gridded time-to-event fits use grid times. (#258, #270)

LTMLE accepts n_bootstrap= for full refits of resampled trajectories or clusters. Unsupported inference settings report bootstrap spreads as diagnostics. (#258)

Diagnostics and sensitivity analyses#

Reports expose more of the fitted mechanisms and distinguish deferred work from unavailable analyses.

Support reports include combined mechanism denominators and the concentration of fitted score weights. These are descriptive measures, without a pass threshold. (#191, #192, #193)

Nuisance reports distinguish collaborative working mechanisms and show variation across repeated splits. Longitudinal reports cover treatment, censoring, outcome, and pseudo-outcome fits. (#194, #195)

Longitudinal truncation curves refit the outcome recursion at each requested mechanism bound. They report estimate movement and score-cell counts, without selecting a preferred bound. (#204)

assess() adds a deferred status for work awaiting arguments or permission to refit. Its summary presents returned analyses before inventories of checks and omissions. (#197, #198)

Changed#

Targeting and uncertainty#

Clustered intervals account for unequal cluster sizes. Eligible fits below 40 contributing clusters use a Student t reference. Point-treatment fits below 10 clusters and longitudinal fits below 20 withhold intervals. Simultaneous bands remain unavailable with a t reference. (#264, #265)

Cross-fitted longitudinal targeting uses a pooled fluctuation over held-out predictions. This changes the fitted construction and can change estimates. (#220)

Omitted-variable bounds refuse unsupported estimator compositions. Plug-in point bounds remain available, but their confidence limits are withheld. Controlled-direct-effect fits no longer return E-values. (#223, #229, #230)

Density fitting and tutorials#

The default density bin count grows with sample size. Density fitting refuses a hazard design that exceeds available memory. (#269)

Method tutorials are executable notebooks with stored outputs. (#213)

Fixed#

Influence curves and bootstrap targets#

ATT and ATC omitted-variable bound standard errors now include uncertainty in the conditioning-arm share. Point bounds are unchanged. (#230)

Ratio-scale contrasts and compositions of transformed estimates now apply influence curves on the correct scale. (#258, #267)

Bootstrap replicates retain the point fit’s resolved estimands. Missing-outcome fits using estimands="all" no longer fail from requesting unsupported replicate targets. (#262)

Constant longitudinal nodes#

Longitudinal nodes with no censoring use a fixed censoring probability of one. Eligible event-free nodes use hazard zero, avoiding classifier failures on constant targets. (#270)

Longitudinal parameters that read a constant node now report constant_node_plugin and withhold confidence intervals and p-values. Derived contrasts and restricted means inherit the status, and simultaneous bands exclude those parameters. (#274)

Compatibility#

cleverly supports Python 3.11, 3.12, and 3.13 with pandas or Polars dataframes.

This remains an alpha release. The package does not promise compatibility for public APIs, CausalStudy objects, pickled objects, or saved results. Follow the upgrade notes when moving an analysis to 0.1.2.

Full changelog: v0.1.1…v0.1.2