Skip to contents

Overview

This vignette defines the terms used throughout the swereg target trial emulation (TTE) system. Use it as a reference when you read or write code that uses TTEDesign, TTEEnrollment or TTEPlan.

Data levels

Term Meaning
skeleton Person-week panel created by create_skeleton() and enriched with registry data. One row per person per ISO week. Input to the TTE pipeline. Stored as batched .qs2 files.
person-week Synonym for skeleton-level data before enrollment. The data_level of a TTEEnrollment starts as "person_week".
trial After enrollment via TTEEnrollment$new(..., ratio = ), data is expanded to trial panels: one row per person per trial per time period. data_level becomes "trial".
counting-process The trial-level data uses counting-process format with tstart/tstop columns (Andersen-Gill style), suitable for time-varying Cox models and weighted Poisson regression.

Time axes

Each trial-level row carries three time axes. One is a function of the other two: period_id = enrollment_period_id + interval number, where the interval number is tstart / period_width + 1.

Term Meaning
period_id The calendar period of a row: of a skeleton week before enrollment, and of a follow-up interval after it. .assign_period_ids() sets it from a fixed calendar origin. The IPCW denominator reads it.
enrollment_period_id The trial: the enrollment period of the person-trial, which ends at time zero. It is constant within a person-trial. The comparator draw and the outcome models read it. The attrition table and the comparator-draw counts that $get_matching() returns carry it as a key column.
time since time zero The weeks from time zero to the start of the follow-up interval, held in tstart (design$tstart_var). Every outcome and censoring model reads it at the interval start, and not at tstop. On the last row of a person-trial, tstop is the week where follow-up stops, which can fall inside the interval.

vignette("tte-methods") section 1.8.9 states which axes each model holds, and why.

Classes

Class Role
TTEDesign Column name mappings that define the trial schema: person ID, treatment, outcome, confounder, and time variables. Created once via TTEDesign$new() and reused across the workflow.
TTEEnrollment Enrollment data container (data.table + design + workflow state). Methods modify in-place via R6 reference semantics and return invisible(self) for $-chaining.
TTEPlan Builder for trial generation. Holds the ETT grid, skeleton file paths, and per-ETT design parameters. Orchestrates Loop 1 via $s1_generate_enrollments_and_ipw().

ETT grid

The rule that separates the two acronyms: TTE names the method and the class prefix, and ETT names one cell of the grid. ETT is always countable. Write “one ETT” or “12 ETTs”. Never write “the ETT approach”, which is TTE.

Term Meaning
ETT (emulated target trial) One combination of outcome × follow-up duration × enrollment_id. Each ETT produces one analysis-ready dataset. Corresponds to one row in plan$ett.
enrollment_id Groups ETTs that share the same trial panels. ETTs within an enrollment_id have the same age group and the same design parameters (confounders, treatment, eligibility). They differ only in outcome and/or follow-up duration.
ett_id Unique identifier for a single ETT (e.g., "ETT01"). Auto-assigned sequentially by $add_one_ett().
enrollment_spec The metadata list returned by plan$enrollment_spec(i). Contains design (TTEDesign), enrollment_id, age_range, and n_threads. Used internally by the two-pass Loop 1 workers.

Two-loop architecture

Loop 1: enrollment + IPW

One iteration per enrollment_id. Run by plan$s1_generate_enrollments_and_ipw():

skeleton files ──(parallel worker subprocesses)──► enroll (draw per enrollment period + collapse)
  ──► rbind ──► impute ──► IPW + truncate ──► save

Produces two files per enrollment_id:

  • file_raw: post-enrollment, pre-imputation
  • file_imp: post-imputation + IPW (input to Loop 2)

Loop 2: per-ETT outcome weighting

One iteration per ETT. Runs sequentially in the main process:

load file_imp ──► $s4_prepare_for_analysis() ──► save file_analysis

$s4_prepare_for_analysis() combines outcome preparation and IPCW-PP into one call. It prepares outcome data, calculates IPCW-PP, combines weights (ipw × ipcw_pp → analysis_weight_pp), and writes the truncated copy analysis_weight_pp_trunc. It keeps the three factors of ipcw_pp as columns.

Weights

Term Meaning
IPW (Inverse Probability of treatment Weighting) Baseline confounding adjustment. Computed once per enrollment_id in Loop 1 via $s2_ipw().
IPCW-PP (Inverse Probability of Censoring Weighting, Per-Protocol) Time-varying weight for per-protocol analysis. Accounts for treatment switching and loss to follow-up. Computed per ETT in Loop 2 via $s4_prepare_for_analysis(). ipcw_pp is the product ipcw_pp_time_zero × ipcw_pp_loss × ipcw_pp_deviation, one factor per censoring model.
loss model The IPCW model for loss of observation, indicator censor_loss. It fits on the rows without an outcome, because loss is observed after the outcome of a row. Its factor is ipcw_pp_loss.
deviation model The IPCW model for protocol deviation, indicator censor_deviation. It fits on the rows without an outcome that were not lost, because a person who is not observed cannot be seen to deviate. Its factor is ipcw_pp_deviation.
deviation at time zero A deviation that stops per-protocol follow-up at time zero, so the person-trial keeps no row. $time_zero_deviation records every person-trial under follow-up at time zero, with deviation_time_zero. A logistic model fitted on that record gives the factor ipcw_pp_time_zero.
not-fitted sentinel list(fitted = FALSE, reason = ) in $ipcw_formulas[[stratum]][[cause]], for a cause with no censoring in its risk set. Its factor is 1.
analysis_weight_pp Final combined weight (ipw × ipcw_pp), not truncated. Created automatically by $s4_prepare_for_analysis().
analysis_weight_pp_trunc analysis_weight_pp truncated at the 1st and 99th percentiles. $s4_prepare_for_analysis() writes it.
truncation Winsorization of extreme weights at the 1st and 99th percentiles to reduce variance. It writes a copy with the suffix _trunc and leaves the original weight unchanged. $s3_truncate_weights() truncates ipw into ipw_trunc, with the percentiles as defaults. $s4_prepare_for_analysis() writes analysis_weight_pp_trunc at percentiles fixed in the code.

File naming

All output files live in the project-specific data directory.

Column in plan$ett Pattern When created
file_raw {prefix}_raw_{enrollment_id}.qs2 Loop 1 (intermediate)
file_imp {prefix}_imp_{enrollment_id}.qs2 Loop 1 (output)
file_analysis {prefix}_analysis_{ett_id}.qs2 Loop 2 (output)

Variable prefixes

Prefix Convention
x_ Loop iteration variables extracted from grid tables (e.g., x_outcome, x_follow_up, x_file_analysis). Used in generate and analysis scripts to distinguish loop variables from dataset columns.
rd_ Row-dependent variables (e.g., rd_age_continuous, rd_intervention). Variables that can change value across rows (time points) for the same person.
ri_ Row-independent variables (e.g., ri_birthcountry, ri_age_first_dx, ri_register_tag). Variables that are fixed per person across all rows. See vignette("rowdep-rowind-concept") for rd_ -> ri_ transformation patterns.

Analysis types

The target trial emulation literature describes three analysis strategies:

Analysis Description swereg support
Intention-to-treat (ITT) Compare initiators vs non-initiators regardless of subsequent adherence. No censoring at treatment switching. Yes. $s4_prepare_for_analysis(estimand = "itt") keeps follow-up through switching (no IPCW); analyse with $irr(weight_col = "ipw_trunc").
Per-protocol Censor at protocol deviation (treatment switching), adjust for informative censoring with IPCW. Yes. $s4_prepare_for_analysis(estimand = "pp") (default) applies per-protocol censoring, then estimates IPCW-PP weights. The final combined weight analysis_weight_pp = ipw × ipcw_pp is used in $irr().
As-treated Model time-varying treatment status with time-varying IPW. Not implemented. Requires time-varying treatment weights P(A_t

The production pipeline produces both estimands per ETT: per-protocol via $irr(weight_col = "analysis_weight_pp_trunc") and intention-to-treat via $irr(weight_col = "ipw_trunc"), reported side by side (and as separate forest plots) in the exported tables.

Minimum-events rule

The flat key min_expected_events_per_arm_per_year of the specification sets the threshold. vignette("tte-methods") section 1.8.6 states the rule.

Term Meaning
follow-up year One 52-week window of follow-up from time zero: (0, 52], (52, 104], and so on. In whole weeks, these are weeks 1 to 52 and weeks 53 to 104. A follow_up that is not a multiple of 52 weeks takes the decision of the ETT at the next whole year. The rule does not judge its partial last year.
expected events An arm’s expected events in a follow-up year: its weighted person-years multiplied by the pooled weighted event rate of both arms in that year. They are computed under the null.
reportable horizon The end of the last follow-up year before the first year in which either arm has fewer than min_expected_events_per_arm_per_year expected events. It is 0 when the first year fails, and the ETT’s follow_up when no year fails.
NE Not estimable. An IRR, risk difference or number needed to treat that the minimum-events rule withheld reads NE in the workbook and in the forest figure.

Enrollment period width

The period_width parameter in TTEDesign (default: 4 weeks) sets the width of an enrollment period. The same width sets each follow-up interval. The input is a person-week skeleton, so eligibility and treatment status are assessed weekly. period_width then groups consecutive weeks into enrollment periods, and each enrollment period opens exactly one trial. With period_width = 4, one trial opens every four weeks, and not one trial per week.

Time zero is a landmark: the first week after the enrollment period closes. A person enters the trial only if they reach that week under observation and free of every enrollment outcome. The enrollment period therefore carries no follow-up and no immortal time. period_width trades the number of trials against how long a newly eligible person waits:

  • Narrower enrollment periods (e.g., period_width = 1): a person waits at most one week for a trial. The cost is more trials and a larger dataset.
  • Wider enrollment periods (e.g., period_width = 4): fewer trials and lower computational cost, at the cost of a wait of up to four weeks.

Caniglia et al. (2023) report a residual immortal time under a different time origin. They set time zero to the first day of the enrollment week and define exposure over that whole week:

“for each trial we defined time zero as the first day of the week and exposure as antibiotic initiation between the first and seventh day of the week. Accordingly, some amount of immortal time bias is still possible.”

“Generally, defining trials on a shorter scale will reduce residual immortal time bias.”

That residual is a property of a time origin that opens before classification ends. swereg opens follow-up at time zero instead, so a shorter enrollment period does not reduce it. See vignette("tte-timing") for the timing rules and worked examples.

swereg implements no grace period. A grace period allows initiation within a fixed window after assignment, and does not count that initiation as a deviation. It requires cloning, censoring and weighting (Hernan 2016, Section 4.4), which this pipeline does not do. period_width gives slack only for the timing of initiation inside the enrollment period. Deviation after time zero censors per-protocol follow-up at the start of the first discordant week beyond the arm’s tolerance. See vignette("tte-methodology") for the same statement, mapped to the reference papers.

Set period_width = 1 when the protocol defines treatment at a single time point. Set it wider when initiation is gradual.

Enrollment period boundaries are anchored to a fixed calendar origin, not to the first observed week of a study. swereg numbers the rows of cstime::dates_by_isoyearweek, which starts at ISO week 1900-01, then assigns period_id = (week_index - 1) %/% period_width. Two studies with different start dates therefore share the same enrollment period boundaries.

The comparator draw

swereg uses incidence density sampling within each sequential trial. Within each enrollment period, it takes a seeded random sample of comparator individuals. The sample size is the stated comparator-to-intervention ratio, for example 5:1, applied to that period’s count of intervention individuals. Where the enrollment period holds fewer comparators than that, the draw takes all of them. The draw is therefore stratified by the period_width-week enrollment period, and not by the week. It reads no other variable. It attaches no comparator individual to an intervention individual, so it forms no matched set, and no later step conditions on one. A person can be an intervention individual in one trial and a comparator individual in another. That property is what names the draw incidence density sampling. It is a design choice for computational efficiency on a large registry dataset.

Alternative approaches described in the literature:

  • No matching, IPW only (Danaei 2013, Hernan 2008): Include all eligible non-initiators, adjust via propensity score. More statistically efficient but computationally expensive with large registries.
  • Propensity score matching (Danaei 2013, sensitivity analysis): Match on estimated propensity score. More complex but can achieve better balance.

swereg combines the draw (for computational tractability) with IPW on the covariates taken at the recruiting week. The IPW step re-weights the drawn sample to balance those covariates.