← Methods repository
concept

Active Comparator, New-User Design

A cohort design that restricts to patients initiating either a study drug or a clinically interchangeable active comparator after a drug-free washout, with follow-up starting at initiation (time zero), to control confounding by indication and prevalent-user bias.

Study_Designactive-comparatornew-user-designincident-userconfounding-by-indicationpharmacoepidemiologyhead-to-headtarget-trialpropensity-score
Methods reference only. Use primary source citations and local policy before applying this in a study protocol, regulatory submission, payer dossier, or clinical decision.

In plain language

The active comparator, new-user design is a way to compare two drugs fairly using everyday healthcare records. You only keep patients who are just starting one of two competing drugs for the same condition (so neither group has been on its drug for years), you make everyone's first fill their shared 'day zero,' and then you watch both groups forward in time under the exact same rules. Comparing two real treatment choices for the same illness — rather than treated patients against untreated ones — keeps the two groups similar, so a difference in outcomes is more likely to be the drug and not the kind of patient who got it. It cannot answer 'is this drug better than no drug,' only 'is drug A better than drug B.'

The active comparator, new-user (ACNU) design combines two restrictions that attack the two dominant sources of bias in observational drug studies. The new-user (incident-user) restriction requires that a patient have no dispensing of the study drug or its comparator during a defined washout, so that follow-up starts at first exposure (time zero) for everyone. The active-comparator restriction chooses the reference group as initiators of a different drug used for the same indication, rather than non-users. Together they emulate the eligibility and treatment-assignment structure of the head-to-head randomized trial you wish you could run.

Core conceptual distinction

Two design choices are doing the work, and they are separable. (1) New-user vs prevalent-user: starting follow-up at initiation removes immortal time, prevents adjustment for post-initiation variables on the causal pathway, and avoids depletion-of-susceptibles (the survivors who tolerate a drug look healthier than incident users). (2) Active comparator vs non-user: comparing two treatment decisions for the same indication removes most confounding by indication and healthy-user/healthy-adherer bias, because both arms cleared the same clinical threshold to be treated. The estimand is the comparative (drug A vs drug B) effect on initiation — an intention-to-treat-like contrast under a first-line strategy, or an as-treated/per-protocol contrast if you censor at switching/discontinuation and weight for informative censoring. ACNU does not estimate "drug vs no drug"; if that is the policy question, the active comparator is the wrong reference.

Pros, cons, and trade-offs

- vs new-user with a non-user / unexposed comparator: ACNU removes confounding by indication and healthy-user bias that cripple drug-vs-no-drug comparisons in claims, and yields better covariate overlap (both arms are treated). Cost: it answers a narrower question and loses power when the comparator is rarely used; if the comparator has its own effect on the outcome, the contrast is shifted, not unbiased for an absolute effect. Prefer ACNU for nearly all comparative safety/effectiveness questions among chronic-disease therapies. - vs prevalent-user / ever-exposed designs: ACNU eliminates survivor bias, depletion of susceptibles, and time-zero misalignment. Cost: smaller cohorts and a population skewed toward initiators, who may differ from the prevalent users who dominate real-world practice. Prefer ACNU when early effects matter or when prevalent-user bias is plausible; consider a prevalent-new-user (Suissa) extension when initiation is too rare. - vs target-trial emulation with clone-censor-weight: ACNU is the analytic core of most two-drug target-trial emulations and is far simpler to specify and defend. Cost: it is less flexible for sustained/dynamic strategies, grace periods that create eligibility-time ambiguity, or multi-option regimens, where g-methods or clone-censor-weight add value. Prefer plain ACNU unless the protocol genuinely requires a dynamic per-protocol estimand.

When to use

Head-to-head comparative effectiveness or safety of two drugs for the same indication in claims, EHR, or registry data; building the analytic engine of a target-trial emulation; any setting where confounding by indication would doom a drug-vs-non-user contrast. A defensible comparator is the linchpin: it should treat the same indication, be a plausible alternative for the same patients at the same decision point, and not itself cause (or prevent) the outcome.

When NOT to use — and when it is actively misleading

- No clinically interchangeable comparator exists. Forcing a comparator that is prescribed to systematically different patients (e.g., a second-line agent vs a first-line agent) re-introduces confounding by indication and channeling — the bias you came to remove. Diagnose with baseline covariate balance and clinical review before trusting the cohort. - The comparator affects the outcome of interest. Comparing two antihypertensives on stroke is fine; comparing them on a renal outcome that one drug class directly modifies makes the "null comparator" assumption false. - The genuine question is drug vs no treatment (e.g., uptake, adherence's effect on cost). ACNU cannot answer it. - Severe non-overlap / positivity violation. If one drug is reserved for sicker or renally-impaired patients, PS distributions separate, matching discards much of the cohort, and the surviving estimand no longer maps to a meaningful population. - One drug is much older. Calendar-time imbalance (the comparator was first-line for a decade before the study drug launched) creates secular confounding; require both drugs to be co-available and consider restricting to overlapping calendar time.

Data-source operational depth

- Claims (FFS or commercial): Exposure is the pharmacy claim (NDC + `fill_date` + `days_supply`). Require continuous medical + pharmacy enrollment across the full washout (commonly 365 days) so the absence of prior dispensing is real, not unobserved. Confirm indication with diagnosis codes in the baseline window. Index date = first qualifying fill. Failure modes: Medicare Advantage and bundled/capitated arrangements drop fee-for-service claims, so "no prior fill" can be missingness, not a true washout — restrict to enrollees with both Parts A/B/D (or commercial pharmacy benefit) and exclude MA-only person-time. Sample fills, 90-day mail-order, and free samples distort `days_supply`. - EHR: Initiation is the order or administration, not the dispensing; linkage to pharmacy fills is preferred to confirm the patient actually started. Problem lists, labs, and notes sharpen indication and baseline severity (an advantage over claims), but visit-driven capture means a patient who leaves the system is differentially lost — define observation windows explicitly and treat loss to follow-up as potentially informative. - Registry: Strongest for indication, disease severity, and adjudicated outcomes (e.g., cancer stage); typically weak for complete pharmacy exposure. Link to claims for the full fill history and to a death index to firm up censoring. - Linked claims–EHR–vital records: The ideal substrate — EHR severity + claims completeness + reliable mortality — but linkage introduces selection (only the linkable subset) and date-discrepancy issues between order, fill, and service dates that must be reconciled before time-zero assignment.

Worked claims example

Question: incident heart failure with second-generation sulfonylurea vs DPP-4 inhibitor among adults with type 2 diabetes in a commercial + Medicare FFS database. (1) Eligibility: age ≥18, ≥2 diabetes diagnoses, and 365 days of continuous A/B/D (or commercial medical+pharmacy) enrollment before the first study fill. (2) Washout: no fill of any sulfonylurea or DPP-4 inhibitor in the 365-day lookback — this is what makes both arms incident users. (3) Time zero: the date of that first qualifying fill; assign the arm from the NDC dispensed on that date. (4) Baseline covariates: measured only in the 365 days up to and including time zero (comorbidities, HbA1c proxies, prior insulin, healthcare utilization), feeding a high-dimensional propensity score. (5) Follow-up: from time zero to first validated HF event, censoring at disenrollment, death, end of data, and — for an as-treated analysis — treatment discontinuation (last `days_supply` end + a pre-specified grace period) or switch to the other arm. (6) Apply 1:1 PS matching (or overlap weighting), check standardized differences <0.1, and run sensitivity analyses on washout length, grace period, and a negative-control outcome to detect residual confounding.

Worked example

Scenario

We want to compare two diabetes drugs on the risk of being hospitalized for heart failure: a sulfonylurea (glipizide, our study drug) versus a DPP-4 inhibitor (sitagliptin, our active comparator). We pull pharmacy claims for two adults with type 2 diabetes. We require each to have a clean 365-day drug-free washout (no fill of either drug class) so both are true first-time starters, set each patient's first qualifying fill as their shared day zero, and follow both forward for 180 days under identical rules to see who has a heart failure hospitalization first.

Dataset

The raw rows an analyst would see in a claims pharmacy table, one row per fill. drug_class flags whether the fill is the study drug or the active comparator.

person_idfill_datedrugdrug_classdays_supply
20012024-01-01glipizideSTUDY90
20012024-04-01glipizideSTUDY90
20022024-01-01sitagliptinCOMPARATOR90
20022024-04-01sitagliptinCOMPARATOR90

Steps

  • Check the washout: for each patient, look back 365 days before their first fill (all of 2023). Neither patient has any glipizide or sitagliptin fill in that window, so both qualify as brand-new starters.

  • Set day zero: patient 2001's first fill (glipizide) and patient 2002's first fill (sitagliptin) are both on 2024-01-01, so both clocks start on the same aligned index date.

  • Assign the arm from the drug filled on day zero: 2001 goes to the STUDY arm, 2002 goes to the COMPARATOR arm.

  • Follow both forward for 180 days (2024-01-01 to 2024-06-29) under identical rules, watching for a heart failure hospitalization.

  • Patient 2001 (study drug) is hospitalized for heart failure on 2024-05-15, which is day 135 of follow-up. Patient 2002 (comparator) reaches day 180 with no event and is censored at the end of the window.

  • Because both patients cleared the same washout, share the same day zero, and follow the same rules, the only structural difference between them is which drug they started.

Result

Of 2 new initiators (1 study, 1 comparator), the study-drug patient had 1 heart failure hospitalization at day 135 of a 180-day follow-up; the comparator patient had 0 events over the full 180 days. Both had a clean 365-day washout and a shared index date of 2024-01-01, so the comparison is of two aligned first-time starters rather than of treated-vs-untreated patients.

Timeline Spec

Title

Active comparator, new-user design: two aligned first-time starters (study drug vs active comparator)

Window
Start

2023-01-01

End

2024-06-29

Label

365-day shared washout, aligned index date 2024-01-01, then 180-day follow-up

Events
  • Label

    Patient 2001 (STUDY) - glipizide Fill 1

    Start

    2024-01-01

    Length Days

    90

    Quantity

    90 days_supply

  • Label

    Patient 2001 (STUDY) - glipizide Fill 2

    Start

    2024-04-01

    Length Days

    90

    Quantity

    90 days_supply

  • Label

    Patient 2002 (COMPARATOR) - sitagliptin Fill 1

    Start

    2024-01-01

    Length Days

    90

    Quantity

    90 days_supply

  • Label

    Patient 2002 (COMPARATOR) - sitagliptin Fill 2

    Start

    2024-04-01

    Length Days

    90

    Quantity

    90 days_supply

Spans
  • Kind

    washout

    Start

    2023-01-01

    End

    2023-12-31

    Label

    365-day drug-free washout (both patients, no study or comparator fill)

  • Kind

    exposed

    Start

    2024-01-01

    End

    2024-06-29

    Label

    Patient 2001 (STUDY) on-treatment follow-up

  • Kind

    followup

    Start

    2024-05-15

    End

    2024-05-15

    Label

    Patient 2001 heart failure hospitalization (day 135)

  • Kind

    exposed

    Start

    2024-01-01

    End

    2024-06-29

    Label

    Patient 2002 (COMPARATOR) on-treatment follow-up, no event

Result
Label

Shared index 2024-01-01; study arm 1 HF event at day 135, comparator arm 0 events over 180 days

Value

135

Caption

Two new users for the same indication start at an aligned day zero after the same 365-day washout: one on the study drug, one on the active comparator. Because baseline is measured before the shared index fill and follow-up begins at the fill under identical rules for both arms, the design controls confounding by indication and removes the head start that prevalent users would have.

Alt Text

Timeline with a 365-day drug-free washout across all of 2023 for both patients, a shared index date on 2024-01-01, and a 180-day follow-up. The study-drug patient (glipizide) has two 90-day fills and a heart failure hospitalization at day 135; the active-comparator patient (sitagliptin) has two 90-day fills and no event through day 180.

Runnable example

python implementation

ACNU cohort construction from claims-style inputs. Required inputs (already cleaned and de-duplicated): rx : pharmacy fills -> person_id, fill_date (datetime), drug_class in {'STUDY','COMPARATOR'}, days_supply enroll : enrollment spans -> person_id,...

import pandas as pd
import numpy as np

WASHOUT_DAYS = 365  # drug-free + continuous-enrollment lookback that defines "new user"

def build_acnu_cohort(rx: pd.DataFrame, enroll: pd.DataFrame) -> pd.DataFrame:
    rx = rx.sort_values(["person_id", "fill_date"])

    # Candidate index = first fill of EITHER the study drug or the active comparator.
    study_fills = rx[rx["drug_class"].isin(["STUDY", "COMPARATOR"])]
    idx = (study_fills.groupby("person_id")
                      .first()
                      .reset_index()
                      .rename(columns={"fill_date": "index_date", "drug_class": "arm"}))

    # New-user check: no fill of study OR comparator in the WASHOUT_DAYS before the index date.
    prior = study_fills.merge(idx[["person_id", "index_date"]], on="person_id")
    prior_in_washout = prior[(prior["fill_date"] < prior["index_date"]) &
                             (prior["fill_date"] >= prior["index_date"] - pd.Timedelta(days=WASHOUT_DAYS))]
    idx = idx[~idx["person_id"].isin(prior_in_washout["person_id"])].copy()

    # Continuous, FFS-observable enrollment spanning the full washout through index (no MA-only gaps).
    e = enroll.merge(idx[["person_id", "index_date"]], on="person_id")
    e["covers"] = ((e["enroll_start"] <= e["index_date"] - pd.Timedelta(days=WASHOUT_DAYS)) &
                   (e["enroll_end"]   >= e["index_date"]) &
                   (~e["ma_only"]))
    eligible = e.loc[e["covers"], "person_id"].unique()

    cohort = idx[idx["person_id"].isin(eligible)].copy()
    cohort["baseline_start"] = cohort["index_date"] - pd.Timedelta(days=WASHOUT_DAYS)  # covariate window
    return cohort[["person_id", "arm", "index_date", "baseline_start"]]
r implementation

ACNU cohort construction with data.table. Inputs mirror the Python version: rx : person_id, fill_date (Date), drug_class in {'STUDY','COMPARATOR'}, days_supply enroll : person_id, enroll_start, enroll_end, ma_only (logical)

library(data.table)
WASHOUT_DAYS <- 365L

build_acnu_cohort <- function(rx, enroll) {
  setDT(rx); setDT(enroll)
  setorder(rx, person_id, fill_date)

  study <- rx[drug_class %chin% c("STUDY", "COMPARATOR")]
  idx <- study[, .(index_date = fill_date[1L], arm = drug_class[1L]), by = person_id]

  # New-user: drop anyone with a study/comparator fill in the washout window before index.
  study <- merge(study, idx[, .(person_id, index_date)], by = "person_id")
  prior_ids <- unique(study[fill_date < index_date &
                            fill_date >= index_date - WASHOUT_DAYS, person_id])
  idx <- idx[!person_id %chin% prior_ids]

  # Continuous FFS-observable enrollment across the full washout through index.
  e <- merge(enroll, idx[, .(person_id, index_date)], by = "person_id")
  ok <- e[enroll_start <= index_date - WASHOUT_DAYS &
          enroll_end   >= index_date & !ma_only, unique(person_id)]

  cohort <- idx[person_id %chin% ok]
  cohort[, baseline_start := index_date - WASHOUT_DAYS]
  cohort[, .(person_id, arm, index_date, baseline_start)]
}