API overview

Literature mapping lives in Methods; DOIs in References. Docstrings on the symbols below also carry # References sections.

Small-n profile

  • recommend_folds · recommend_run_options · recommend_learners
  • SMALL_N_SL_LEARNERS · adaptive_learners · warn_if_folds_too_large

LMTP and policies

  • run_lmtp_grid · lmtp_tmle_contrast · ShiftPolicy
  • plot_mtp_curve · mtp_curve! · has_makie
  • additive_shift_policy · multiplicative_shift_policy · threshold_shift_policy
  • SequentialPolicy · run_sequential_lmtp · sequential_identification_certificate
  • SurvivalPolicy · run_survival_lmtp · survival_identification_certificate
  • RepeatedOutcomeMSM · run_repeated_outcome_msm · msm_contrast · unstack_repeated_outcomes · identify_repeated_outcomes
  • ParametricRepeatedOutcomeMSM · run_parametric_repeated_msm · simulate_mean_treatment_time_msm
  • build_lmtp_fold_cache

The typed estimands used by these runners are documented with their public constructors:

CausalTargeted.LongitudinalPolicy — Type
LongitudinalPolicy(trt, outcome, adjustment, shift, treat_lag, outcome_lag)

Pathway exposure at treat_lag on AUC outcome at outcome_lag (temporal ID).

source
CausalTargeted.DiscreteTreatmentPolicy — Type
DiscreteTreatmentPolicy

Modified treatment policy on a finite exposure. Recode maps, a static do(A = a*), or a user function (a, wrow) -> a' (R lmtp shift). mtp=true when the rule depends on the natural value of A.

source
CausalTargeted.msm_contrast — Function
msm_contrast(result, i, j) -> NamedTuple

Wald inference for $\tau_i - \tau_j$ using the joint covariance in result.

source
msm_contrast(result, c) -> NamedTuple

Wald inference for the linear form $c^\top\tau$ with $\mathrm{Var}=c^\top\Sigma c$.

source
CausalTargeted.suggest_family_outcome — Function
suggest_family_outcome(y) -> Symbol

Return :binomial when all non-missing values lie in $\{0, 1\}$; :negbin or :poisson for nonnegative integer counts (overdispersion heuristic); otherwise :gaussian. Use with recommend_run_options(...; outcome=) or pass the result as family_outcome on LMTP runners (#34, #36).

source

Discrete LMTP, hurdle, and MMRM

  • run_discrete_lmtp · run_discrete_lmtp_contrast · DiscreteTreatmentPolicy
  • run_estimation_plan · run_two_part_discrete_lmtp · run_two_part_discrete_lmtp_contrast
  • TwoPartInterventionalMean · run_two_part_discrete_lmtp · run_two_part_discrete_lmtp_contrast
  • fit_mmrm · run_mmrm · MMRMResult (requires using MixedModels)
  • suggest_family_outcome · validate_family_outcome

Parametric g-computation

  • fit_parametric_gcomp · ParametricGComputationFit · MixedModelGComputationFit
  • gcomp_mean · gcomp_contrast · gcomp_interaction · run_parametric_gcomp
  • mixed_g_computation · MixedGComputationResult · StratifiedMixedGComputationResult for repeated-outcome compatibility
  • fit_profiled_nb2 · NB2RandomInterceptModel for estimated-shape NB2 mixed fits

fit_parametric_gcomp defaults to the GLM backend. Set backend=:mixed and provide id after loading MixedModels, FastGaussQuadrature, NLopt, and SpecialFunctions for supported mixed fits. See Methods for the supported model, prediction, and inference combinations. Target data can omit the outcome; the repeated-outcome compatibility wrappers retain their existing static-treatment and observed-visit contract.

Mediation

Mediation estimation lives in CausalMediation.jl. After using CausalMediation, prefer run_mediation / run_mediation_grid / MediationSpec there. This package keeps LMTP / certificates / Super Learner only.

Positivity and sensitivity

  • positivity_report · positivity_markdown · attach_positivity_summary!
  • tipping_point_bias · partial_r2_calibration · sensitivity_report · sensitivity_markdown
  • adjustment_set_disagreement · discovery_adjustment_sensitivity · merge_discovery_sensitivity!

Super Learner

  • fit_super_learner · predict_super_learner · SuperLearnerFit · nested_sl_candidate
  • design_matrix
  • Libraries: DEFAULT_SL_LEARNERS, RICH_SL_LEARNERS (includes :randomforest), SMALL_N_SL_LEARNERS; opt-in trees :randomforest / :xgboost after loading MLJDecisionTreeInterface / MLJXGBoostInterface (see Methods)
  • Metalearners: :nnls (default for gaussian; R method.NNLS), :nnloglik (default for binomial; R method.NNloglik), :cv_selector (discrete Super Learner; alias :winner), :invmse. Deprecated: :discrete currently aliases :nnls.
  • family=:multinomial returns an n × K simplex from predict_super_learner.
  • Categorical treatment: DiscreteTreatmentPolicy / run_discrete_lmtp (T=1) and SequentialPolicy policies (multi-time factor recodes). Classification density ratios; TMLE.jl keeps static point-treatment ATE.

Categorical adjustment variables are handled automatically by CausalTargeted's g-computation, LMTP (Gaussian, classification, and hybrid density ratios), LMTP fold-cache, sequential LMTP, survival LMTP, repeated-outcome MSM, and missing-data nuisance pathways. Numeric, Bool, String, and explicit categorical-array columns may be passed without manual dummy coding. A stable internal numeric representation is fitted on the cleaned analysis data and reused across folds. Integer columns are numeric unless explicitly converted to categorical. Continuous MTP (ShiftPolicy / run_lmtp_grid) still requires a numeric exposure. Finite-support treatments use DiscreteTreatmentPolicy / run_discrete_lmtp (T=1) or SequentialPolicy policies (multi-time). Mixed continuous/discrete sequential A_t is rejected.

CausalMediation mediation grids reuse the same fold-stable schema for mixed baseline types.

Planning and certificates

  • plan_mtp · summarise_plan · execute_estimand · estimand_from_query
  • identification_certificate · certificate_dict
  • build_run_metadata · attach_run_metadata!
  • test_implied_hurdle_independences · local_markov_statements · IndependenceStatement · default_hurdle_label_to_col

identification_certificate(...; provenance=CDMProvenance(...)) carries declared graph, mechanism, observation, policy, exogenous, numerical, scale, and coupling identifiers into certificate_dict. Function implementations are not fingerprinted: supply explicit stable identifiers in CDMProvenance.

The returned metadata includes certificate_schema_version = "cdcs.certificate.v2". Semantic identifiers remain distinct from run-time fields such as package version, Julia version and execution time.

CausalTargeted.CausalTargeted — Module
CausalTargeted

Cross-fitted targeted inference: LMTP, Super Learner, certificates, and grid execution. Identification is delegated to CausalDynamics.jl. Mediation EIF / TE / NDE / NIE live in CausalMediation.jl (using CausalMediation).

Small-n profiles, positivity atlases, and sensitivity helpers target conservation and other low-sample causal applications.

Documentation

  • Methods ↔ literature: docs/src/methods.md
  • Full bibliography (DOIs / BibTeX keys): docs/src/references.md
  • Small-n checklist: docs/src/small_n.md

Canonical papers: Díaz et al. (2023) LMTP; van der Laan & Rose (2011) TMLE; Cinelli & Hazlett (2020) sensitivity. For mediation, see CausalMediation (Díaz & Hejazi 2020; Liu et al. 2024).

source
CausalTargeted.recommend_run_options — Function
recommend_run_options(n; engine, n_mediators, rich) -> NamedTuple

Kwargs suitable for run_lmtp_grid / run_mediation_grid / execute_estimand under a small-n-first policy. Pass outcome= (a column vector) to add family_outcome via suggest_family_outcome.

nfoldslearnersdensity_ration_mc (mediation)parallel
< 402smallgaussian64–128false
40–793defaultgaussian64false
≥ 803–5default/richhybrid if rich32–64false*

* Parallel remains off by default for memory safety; set parallel=true explicitly.

source
CausalTargeted.run_lmtp_grid — Function
run_lmtp_grid(data, trt, outcome; baseline, kwargs...) -> DataFrame

Cross-fitted SuperLearner LMTP TMLE grid matching R run_lmtp_grid() (shift_scale = "z").

Uses clamp-aware hybrid targeting: when many observations hit clamp bounds, the TMLE fluctuation is down-weighted toward g-computation.

Defaults:

  • density_ratio = :gaussian (stable at sheep n; use :hybrid / :classification for large n)
  • cv_trunc = false (prespecified trunc; opt-in variance heuristic is not cross-validation)
  • estimator = :tmle (score-solving; pass :sdr / :eif / :itmle as needed)
  • epochs = 1 (do not inherit mediation-grid epochs=30)
  • simultaneous = true adds multiplier-bootstrap simultaneous bands
  • parallel = true when Threads.nthreads() > 1
  • cache_nuisances = true reuses fold outcome / exposure models across δ

Quantile clamping creates boundary masses under a continuous treatment law. Finite score-based limits are therefore labelled :approximate_clamped_policy, not claimed as regular nonparametric EIF intervals. Overlap, truncation and weakened targeting require empirical calibration for the selected target.

source
CausalTargeted.run_repeated_outcome_msm — Function
run_repeated_outcome_msm(df, treatment, outcomes; baseline, strata, propensity,
                         folds, learners, rng, handle_missing, estimator, cluster)
    -> NamedTuple

Estimate $\tau(t)$ for binary point treatment and several outcomes with a joint influence-function covariance.

Returns (estimates, se, covariance, ic, outcomes, n, positivity, missingness, …). Use msm_contrast for linear forms $c^\top\tau$ (e.g. $\tau(t_3)-\tau(t_2)$).

Missingness uses a shared sample across times (complete-profile $R$). estimator=:tmle (default) applies a per-fold clever-covariate fluctuation; :eif is the untargeted AIPW one-step.

strata may be one Symbol or a vector of symbols. Nuisance models are still fit on the full eligible sample, with these columns added to baseline, while targeting and Hajek standardisation are conditional on each joint stratum. propensity may be a known scalar, column symbol, or input-row-aligned vector; known values bypass treatment fitting but retain positivity diagnostics.

cluster may be a column Symbol in df or a length-nrow(df) id vector. When set, $\widehat{\Sigma}$ is cluster-robust (sampling hierarchy). This does not change the estimand to BLUP / partial pooling.

source
CausalTargeted.run_parametric_repeated_msm — Function
run_parametric_repeated_msm(df, treatment, outcomes; baseline, design, target, ...)
    -> NamedTuple

Estimate a parametric MSM by GLS projection of the unstructured repeated-outcome IF estimates from run_repeated_outcome_msm.

strata and propensity are passed through to the unstructured fit. A stratified projection requires an explicit K*T × p design for target=:tau or 2*K*T × p for target=:mean; symbolic T-row designs are rejected.

Returns (coefficients, se, covariance, coef_names, fitted_tau, design, target, outcomes, n, positivity, missingness, …).

source
CausalTargeted.positivity_report — Function
positivity_report(data, trt; deltas, stratify_by, lower_q, upper_q, shift_scale, kwargs...) -> DataFrame

Tidy atlas of support / clamp diagnostics across the δ-grid and strata.

Uses support_diagnostics and additive_clamp_diagnostics. Statuses: ok, weak_support, unsupported_shift.

source
CausalTargeted.SequentialPolicy — Type
SequentialPolicy(treatments, outcome, baseline; time_vary, shift, policies)

Time-ordered treatments A_1,…,A_T, baseline covariates L_0, and optional time-varying covariates time_vary[t] observed before A_t.

Empty policies selects the numeric additive-shift path. A nonempty vector of DiscreteTreatmentPolicy (length T, or length 1 broadcast to every time) selects dummy-coded factor recodes. Mixed continuous and categorical A_t is not supported.

source
CausalTargeted.estimand_from_query — Function
estimand_from_query(query::CausalQuery, adjustment; mediators, shift, policies, treatments, time_vary) -> Estimand

Map a CausalDynamics query to a typed estimand.

source

MTP effect curves

These functions visualise effects that have already been estimated; they do not fit an MTP estimator or identify a causal effect. Interval columns can be pointwise or simultaneous bands. Set ylabel to describe the intervals passed to the function whenever the default "Estimated effect (95% CI)" is not accurate.

Loading CairoMakie activates both the vector API and the DataFrame convenience interface:

CausalTargeted.has_makie — Function
has_makie() -> Bool

Return true when the optional CausalTargetedMakieExt plotting extension is loaded. Loading a Makie backend such as CairoMakie loads Makie and activates the extension.

source
CausalTargeted.mtp_curve! — Function
mtp_curve!(ax, shift, estimate, lower, upper;
    clamp=nothing, estimand=nothing, panel_mode=false,
    ribbon_alpha=0.18, strip_gap_fraction=0.020,
    strip_height_fraction=0.055)

Draw already-estimated modified-treatment-policy (MTP) effects into an existing Makie Axis. This function performs no causal estimation.

The four required vectors contain shift values, point estimates, and lower and upper interval limits. estimand may contain TE, NDE, and NIE labels and defaults to TE for every row. clamp contains optional proportions clamped by the treatment policy; finite values are squished to [0, 1]. Missing or non-finite clamp values are omitted. Required numeric values must be finite, lower <= upper, and all vectors must have equal lengths.

Rows are copied and sorted by shift within the stable estimand order TE, NDE, NIE. Clamp values repeated across estimands must agree at each shift. The returned named tuple contains plot handles plus series and clamp_geometry metadata, making the result composable and inspectable without mutating inputs.

Keywords

  • panel_mode=false: use compact line and marker sizes suitable for a manually composed faceted layout when true.
  • ribbon_alpha=0.18: interval-ribbon opacity.
  • strip_gap_fraction=0.020: gap below the effect range as a fraction of its y span.
  • strip_height_fraction=0.055: clamp-strip height as a fraction of its y span.
source
CausalTargeted.plot_mtp_curve — Function
plot_mtp_curve(shift, estimate, lower, upper;
    clamp=nothing, estimand=nothing, title=nothing,
    xlabel="Shift (SD units)", ylabel="Estimated effect (95% CI)",
    figure_size=(8.5, 4.5), base_size=12,
    ribbon_alpha=0.18, strip_gap_fraction=0.020,
    strip_height_fraction=0.055) -> Figure, Axis

Create one complete Makie MTP effect-curve figure and return (figure, axis). The function visualises supplied estimates and intervals; it does not estimate causal effects. Intervals may be pointwise or simultaneous—the configurable ylabel should describe whichever interval the caller supplied.

figure_size is measured in inches. The default physical canvas is 8.5 × 4.5 inches, represented internally at 120 Makie layout units per inch. title is left aligned. The remaining data and strip keywords have the same meaning and validation as mtp_curve!. If no finite clamp values are supplied, the clamp strip and colourbar are omitted. Only estimands present in the data appear in the top legend, ordered TE, NDE, NIE.

Export at exact physical size

For a returned fig, PDF uses pt_per_unit = 72 / 120; 320-dpi PNG uses px_per_unit = 320 / 120:

save("mtp_curve.pdf", fig; pt_per_unit = 72 / 120)
save("mtp_curve.png", fig; px_per_unit = 320 / 120)
source
plot_mtp_curve(df;
    shift=:delta, estimate=:est, lower=:lwr, upper=:upr,
    clamp=:clamp, estimand=:estimand, kwargs...) -> Figure, Axis

DataFrame convenience interface for plot_mtp_curve. Its defaults match the output of run_lmtp_grid, so plot_mtp_curve(grid) works directly. Required column selectors are shift, estimate, lower, and upper. The estimand column is optional and defaults to TE when absent or when estimand=nothing; the optional clamp column is similarly ignored when absent or disabled. A single error lists every missing required column. Column vectors are never mutated.

Load a Makie backend such as CairoMakie to activate this method. Other keywords, including title, xlabel, ylabel, and figure_size, are forwarded to the vector API. To plot simultaneous bands returned by run_lmtp_grid, pass lower=:lwr_sim, upper=:upr_sim, and an appropriate ylabel.

source

The DataFrame defaults match run_lmtp_grid, including the optional clamp strip:

using CausalTargeted, CairoMakie

grid = run_lmtp_grid(data, :A, :Y; baseline = [:W])
fig, ax = plot_mtp_curve(grid; title = "Exposure → outcome")

For simultaneous intervals produced by the grid estimator, select those columns and label them explicitly:

fig, ax = plot_mtp_curve(
    grid;
    lower = :lwr_sim,
    upper = :upr_sim,
    ylabel = "Estimated effect (simultaneous 95% band)",
)

Synthetic TE/NDE/NIE example

using CausalTargeted, CairoMakie, DataFrames

shifts = [-0.75, -0.5, -0.25, 0.0, 0.25, 0.5, 0.75]
estimands = ["TE", "NDE", "NIE"]
df = DataFrame(
    delta = repeat(shifts, length(estimands)),
    estimand = repeat(estimands; inner = length(shifts)),
)
scale = Dict("TE" => 0.12, "NDE" => 0.08, "NIE" => 0.04)
df.est = [scale[e] * sinpi(x) for (x, e) in zip(df.delta, df.estimand)]
df.lwr = df.est .- 0.035
df.upr = df.est .+ 0.035
df.clamp = repeat([0.42, 0.28, 0.14, 0.03, 0.16, 0.30, 0.45], length(estimands))

fig, ax = plot_mtp_curve(df; title = "Synthetic exposure → outcome")
fig
Example block output

For custom multi-panel layouts, create ordinary Makie axes and compose the curve-level primitive directly:

panel = Figure()
ax = Axis(panel[1, 1]; title = "Panel A")
handles = mtp_curve!(ax, delta, estimate, lower, upper; clamp, estimand)

The default canvas uses 120 Makie layout units per inch. Save the exact 8.5 × 4.5 inch curve as PDF or 320-dpi PNG with:

save("mtp.pdf", fig; pt_per_unit = 72 / 120)
save("mtp.png", fig; px_per_unit = 320 / 120)