← Methods repository
CONCEPTFOUNDATIONALPYTHON · R · SAS4 citations

Retrospective Cohort Study Design

An observational cohort design built entirely from already-recorded data, in which exposure status is assigned at a time-zero in the past and the cohort is then followed forward through the existing record to ascertain outcomes, so that both the exposure decision and the follow-up have already occurred by the time the study begins.

Study Designlongitudinalcohortstudy-designclaimsehrtarget-trialperson-time
On this page
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

A retrospective cohort study answers a cause-and-effect question (does taking drug A change a patient's risk of outcome B?) using health records that were already collected for other reasons, like insurance billing or routine care. The analyst picks a 'day zero' for each patient that sits in the past, splits people into groups by what treatment they were on at that moment, and then reads forward through the already-written record to see who had the outcome. The follow-up still runs forward in time, exactly like a study that enrolls patients and waits; the only difference is that everything has already happened by the time the researcher sits down. Its big payoff is speed and size, but it can only ever measure things the original record happened to capture.

When to use it
When the exposure and outcome are codeable, the outcome is rare or long-latency, or a large real-world sample is needed for subgroups and precision.
For incidence, natural-history, HCRU, and single-exposure questions; switch to ACNU for head-to-head comparative drug safety/effectiveness.
Always specify the target trial first; implement it through the retrospective-cohort structures here.
Watch out for
Limited to recorded constructs (no biospecimens, protocolized PROs, or adjudicated fixed-visit endpoints without linkage); routine-data coding/selection biases; cannot enforce protocol timing.
A generic retrospective cohort lacking the active-comparator + new-user restrictions is far more susceptible to confounding by indication and prevalent-user bias.
Without the explicit target-trial layer (protocol mapping, assignment, causal contrast), a raw retrospective cohort is where time-zero errors and self-inflicted bias enter.

A retrospective cohort (also historical or non-concurrent cohort) follows the same exposure-to-outcome logic as a prospective cohort, but does so inside data that already exist. The investigator identifies a cohort by exposure status at a past time-zero (index), then "follows" each person forward through the recorded data — claims, electronic health records (EHR), registries, or linked sources — to observe outcomes, censoring, resource use, or other endpoints that have, in calendar time, already happened. The defining feature is temporality of data capture, not the direction of inference: like any cohort, it moves exposure → outcome; unlike a prospective cohort, the data were collected before the research question was posed and for reasons other than the study (billing, care delivery, surveillance).

Core conceptual distinction — design vs estimand vs data

Three things must be held apart and pre-specified.

  1. The design fixes time-zero, eligibility, the exposure contrast, and the censoring rules.
  2. The estimand — the causal contrast (e.g., a per-protocol vs intention-to-treat-analogue hazard ratio, cumulative incidence, or rate difference) and the target population — dictates the model, not the reverse. A retrospective cohort can support a cause-specific hazard, a subdistribution effect under competing risks, restricted mean survival time, or a rate ratio; the design does not choose for you.
  3. The data constrain which estimands are even identifiable. The modern, defensible way to specify all three at once is target-trial emulation: write down the protocol of the randomized trial you wish you could run (eligibility, treatment strategies, assignment, time-zero, outcome, causal contrast, analysis), then build the retrospective cohort to emulate it. Retrospective cohorts that are not anchored to an explicit time-zero and a clear estimand are where immortal time, prevalent-user bias, and post-baseline adjustment silently enter.

Pros, cons, and trade-offs

  • vs prospective cohort: The retrospective cohort uses data that already exist, so it is fast, large, inexpensive at the margin, and can deliver long follow-up the day the study starts — decisive when the outcome is rare or the latency is long, or when prospective enrollment would be unethical or impractical. Cost: you are limited to what was recorded; no biospecimens, no protocolized PROs, no adjudicated endpoints at fixed visits unless you add linkage or a hybrid arm. Prefer retrospective for comparative safety/effectiveness, drug-utilization, and HCRU questions where the constructs are codeable; prefer prospective when the exposure or outcome cannot be reconstructed from routine data with acceptable misclassification.
  • vs nested case-control / case-cohort within the same source: The full retrospective cohort retains person-time for every member, supports time-varying exposure and absolute-risk estimands, and is reusable for multiple outcomes. Cost: it is more computationally and data-management intensive than sampling controls. Prefer the full cohort when you need rates, cumulative incidence, or several endpoints; prefer nested sampling when an expensive covariate (chart review, biomarker) must be collected on a subset.
  • vs self-controlled designs (SCCS, case-crossover): Self-controlled designs eliminate all time-fixed confounding by using the person as their own control, which a between-person retrospective cohort cannot. Cost: they require a transient exposure and an acute outcome and cannot estimate effects of stable exposures. Prefer self-controlled for acute-on-transient questions (e.g., vaccine-fever); prefer the cohort for chronic therapies and absolute risk.
  • vs prevalent-user / cross-sectional analyses of the same data: A new-user retrospective cohort aligns time-zero at initiation and so avoids depletion of susceptibles and adjustment for post-initiation variables. Cost: smaller N and a population skewed toward initiators. This is a variant choice within the retrospective cohort, not a different data source.

When NOT to use — and when it is actively misleading or dangerous

  • No clean time-zero exists. If you start follow-up at a point everyone in one arm has already survived to (e.g., follow-up from a procedure date but classifying exposure by a prescription filled later), you manufacture immortal time that spuriously favors the exposed. If you cannot place a single, arm-symmetric time-zero, do not run the cohort as specified — restructure or use a self-controlled design.
  • Exposure or outcome cannot be reconstructed. Over-the-counter drugs, inpatient-administered agents invisible in pharmacy claims, samples, and outcomes with no validated algorithm produce differential misclassification that no adjustment fixes.
  • Prevalent-user contrast with depletion of susceptibles. Comparing current users to non-users on routine data embeds survivor bias and adjustment for mediators; a naive prevalent-user cohort here is worse than no study.
  • Person-time is unobservable or differentially missing. In claims, Medicare Advantage (MA) enrollees generate no fee-for-service (FFS) claims, so their exposures and outcomes are invisible; counting MA person-time as "unexposed and event-free" biases rates. Likewise, EHR follow-up ends silently when a patient leaves the system.
  • Competing risks ignored in an elderly or sick cohort. When death competes with the outcome and competing-event rates differ by exposure (common in older claims populations), a naive cause-specific Kaplan-Meier over-states cumulative incidence; the estimand (cause-specific vs subdistribution) must be chosen deliberately.

Data-source operational depth

  • Claims (FFS or commercial): The substrate is eligibility, medical, and pharmacy files. Establish observable person-time from enrollment spans, and require continuous enrollment (medical + pharmacy) across the full lookback so that "no prior event" is genuine absence, not unobserved care. Exposure comes from pharmacy claims (`ndc`, `fill_date`, `days_supply`) and procedures (CPT/HCPCS, ICD-10-PCS); diagnoses (ICD-10-CM) serve eligibility, covariates, and validated outcome algorithms. Failure modes and workarounds: (a) MA-only person-time lacks FFS claims — restrict to enrollees with the relevant benefit (Parts A/B/D, or commercial medical+pharmacy) and exclude MA-only spans rather than treating them as event-free; (b) adjudication/claims lag truncates recent person-time — apply a data-cutoff buffer or restrict to fully run-out claims; (c) 90-day mail-order and free samples distort `days_supply` and washout — model supply windows explicitly; (d) death is often unobserved in commercial claims — link to a death index or treat disenrollment as potentially informative censoring.
  • EHR: Richer baseline (labs, vitals, severity, notes via NLP) and some outcomes, but visit-driven, irregular observation: a patient who stops visiting is differentially lost, not event-free. Define observation windows and a loss-to-follow-up rule (e.g., no encounter > N months) explicitly. Exposure is the order/administration, not the dispensing — link to pharmacy fills to confirm the patient actually started. Hybridize with claims for complete pharmacy and HCRU capture.
  • Registry: Strong, validated phenotypes and clinical endpoints (cancer stage, adjudicated events) but typically incomplete longitudinal exposure; link to claims for the full fill history and to a death index for censoring. Registry inclusion criteria bound generalizability.
  • Linked claims–EHR–vital records: Maximizes exposure completeness, baseline severity, and mortality, but linkage selects only the linkable subset and creates order/fill/service date discrepancies that must be reconciled before time-zero assignment; propagate linkage uncertainty into sensitivity analyses.

Worked claims example

Question: among adults with type 2 diabetes initiating a second-generation sulfonylurea, what is the 2-year cumulative incidence of hospitalized heart failure, in a commercial + Medicare FFS database?

  1. Source population and eligibility: age ≥ 18, ≥ 2 outpatient or 1 inpatient diabetes diagnosis (ICD-10-CM E11.x), and 365 days of continuous medical + pharmacy (or A/B/D) enrollment before the first qualifying fill, with all MA-only person-time excluded.
  2. Time-zero / index: the date of the first sulfonylurea fill (`ndc` on `fill_date`) after a clean 365-day washout with no prior sulfonylurea dispensing — this makes the cohort incident users and fixes a single, well-defined start of follow-up.
  3. Exposure assignment: defined at index from the dispensed `ndc`; an as-treated variant would stitch `days_supply` into episodes with a grace period and censor at discontinuation.
  4. Baseline covariates: measured only in the 365-day pre-index window (comorbidities, prior insulin, baseline HCRU, comorbidity index) — never using any post-index information, to avoid conditioning on mediators.
  5. Follow-up and outcome: from index to the first hospitalized HF event (a validated inpatient ICD-10-CM algorithm), applied identically across the cohort.
  6. Censoring: at disenrollment (from eligibility spans), death (linked index), end of data, or 2 years, whichever comes first — and, because death competes with HF in this older population, report the subdistribution cumulative incidence (Fine-Gray / Aalen-Johansen) rather than a naive 1−KM.
  7. Sensitivity: vary washout length (180 vs 365 days), redefine the grace period for the as-treated analysis, and add a negative-control outcome to probe residual confounding.

Decision diagram

flowchart TD
  A[Source population in historical window<br/>continuous enrollment, observable person-time] --> B[Time-zero / index<br/>first qualifying event after washout]
  B --> C[New-user restriction<br/>no qualifying event in washout lookback]
  C --> D[Assign exposure at/before index<br/>new-user vs prevalent; dose; arm from NDC]
  D --> E[Baseline covariates measured<br/>PRE-INDEX ONLY -> PS / hdPS]
  E --> F[Follow-up from index<br/>validated outcome algorithm; update exposure if as-treated]
  F --> G[Censor at disenrollment / death / end of data / switch / competing event]
  G --> H[Analysis per estimand<br/>cause-specific vs subdistribution; rates; RMST]
  H --> I[Sensitivity<br/>washout length, grace rules, negative control, quantitative bias]
Operational flow for retrospective cohort construction and analysis in claims/EHR/registry data — baseline is measured strictly before index, follow-up and outcomes strictly after, with explicit censoring and an estimand-driven analysis.
gantt
  title Retrospective cohort timeline for one new initiator (claims)
  dateFormat YYYY-MM-DD
  axisFormat %b %Y
  section Already in the past
  Continuous FFS enrollment + washout (no prior qualifying event) :done, wash, 2021-01-01, 2021-12-31
  section Time zero
  First qualifying event -> exposure assigned :milestone, t0, 2022-01-01, 0d
  section Follow-up (also in the past)
  Observable person-time, outcome ascertainment :active, fu, 2022-01-01, 720d
  Censor at disenroll / death / data end / switch :crit, cen, 2023-12-21, 1d
Although the analysis is run today, the entire timeline — washout, time-zero, and follow-up — has already occurred in the data. Baseline precedes index and follow-up follows it, so there is no immortal time.

Worked example

Scenario

It is 2026 and we want to know whether adults who start a new diabetes pill go on to be hospitalized for heart failure. Instead of enrolling patients and waiting two years, we open an insurance claims database that already covers 2021 through early 2024. We follow one patient, person 5001, who first filled the new pill on 2022-01-01. Everything in this story already happened years ago; our job is just to read the record in the right order, looking back before that fill to confirm she is a new user, then looking forward to see if and when the outcome occurred.

Dataset

The kind of rows an analyst actually sees: one enrollment span telling us when the insurer could observe her, plus the dated events (a prior fill check, her first qualifying fill, and a later hospitalization).

person_idrecord_daterecord_typedetail
50012021-01-01enrollment_startcontinuous coverage begins
50012021-12-31lookback_checkno diabetes-pill fill in prior 365 days -> new user
50012022-01-01index_fillfirst fill of the new diabetes pill (time-zero)
50012023-06-15outcomehospitalized for heart failure
50012024-03-01enrollment_endstill covered through end of available data
FIG. 1 — DESIGN TIMELINE
Horizontal timeline from 2021 to early 2024. A shaded 365-day look-back block runs from 2021-01-01 to 2021-12-31, then a time-zero marker at 2022-01-01, then a longer forward follow-up block of 530 days ending at an outcome marker on 2023-06-15. A note states the whole timeline was already recorded before the 2026 analysis.
Time-zero (2022-01-01) sits in the past. To its left is the 365-day look-back the analyst reads to confirm a new user and capture baseline health; to its right is forward follow-up through the already-recorded data, ending at the heart-failure event on day 530. The follow-up direction is forward, identical to a prospective study; only the recording happened earlier.

Steps

1Set time-zero (day zero) to her first qualifying fill on 2022-01-01; this is the day she joins the new-user group, and it sits squarely in the past.
2Look BACK across the 365 days before time-zero (2021-01-01 to 2021-12-31) and confirm she had continuous coverage and no earlier fill of this drug class, so she truly is a brand-new user and we can measure her starting health from that window only.
3Look FORWARD from time-zero through the already-written record, watching for the outcome; she is hospitalized for heart failure on 2023-06-15.
4Count the follow-up time from day zero to the event: 2022-01-01 to 2023-06-15 is 530 days, about 17.4 months.
5If no event had appeared, we would have followed her until coverage ended or until a fixed 2-year (730-day) cap, then censored her there rather than assume she stayed event-free.

Result

Follow-up from time-zero (2022-01-01) to the heart-failure hospitalization (2023-06-15) = 530 days = 17.4 months. This single event would later be pooled with every other patient's person-time to estimate a rate; the design's whole job was to place day zero correctly and read look-back before it and follow-up after it.

Trade-offs

Pros of this
Uses existing data — fast, large, inexpensive, with long follow-up immediately available; reflects routine practice and heterogeneity; feasible when prospective follow-up is unethical or impractical.
Pros of this
Supplies the general retrospective-cohort scaffold (time-zero, washout, follow-up, censoring, pre-index covariates) and accommodates prevalent, as-treated, landmark, and external-control variants beyond a two-drug contrast.
Pros of this
Provides the concrete data-construction backbone (cohort plumbing, observable person-time, censoring) on which an emulation is implemented.
Pros of this
Applies study design (time-zero, exposure definition, follow-up, censoring) on top of cleaned data.
Cons of this
Depends entirely on correct low-level claims processing (enrollment derivation, clean claims, reversals, payer heterogeneity); invalid extracts invalidate any cohort.
When to prefer Establish valid claims processing first, then layer the retrospective-cohort design rules.

Runnable example

Retrospective cohort CONSTRUCTION (not estimation) from claims-style inputs. Required inputs (already cleaned and de-duplicated): events : qualifying exposure/dx/px events -> person_id, event_date (datetime), event_type (e.g.

requires: pandas
import pandas as pd

WASHOUT_DAYS = 365   # clean lookback that defines an incident (new) user
MAX_FOLLOWUP = 730   # 2-year administrative cap

def build_retro_cohort(events: pd.DataFrame, enroll: pd.DataFrame) -> pd.DataFrame:
    events = events.sort_values(["person_id", "event_date"])

    # Time-zero = first qualifying event per person.
    idx = (events.groupby("person_id", as_index=False)
                 .first()
                 .rename(columns={"event_date": "index_date"}))

    # New-user check: no qualifying event in the WASHOUT_DAYS before index.
    prior = events.merge(idx[["person_id", "index_date"]], on="person_id")
    had_prior = prior[(prior["event_date"] < prior["index_date"]) &
                      (prior["event_date"] >= prior["index_date"] - pd.Timedelta(days=WASHOUT_DAYS))]
    idx = idx[~idx["person_id"].isin(had_prior["person_id"])].copy()

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

    # Observable follow-up END = first of: end of the FFS span covering index, or the admin cap.
    post = enroll[(~enroll["ma_only"])].merge(cohort[["person_id", "index_date"]], on="person_id")
    post = post[(post["enroll_start"] <= post["index_date"]) & (post["enroll_end"] >= post["index_date"])]
    span_end = post.groupby("person_id")["enroll_end"].max()
    cohort = cohort.join(span_end.rename("ffs_end"), on="person_id")

    cohort["baseline_start"] = cohort["index_date"] - pd.Timedelta(days=WASHOUT_DAYS)  # covariate window
    admin_cap = cohort["index_date"] + pd.Timedelta(days=MAX_FOLLOWUP)
    cohort["censor_date"] = cohort[["ffs_end"]].assign(cap=admin_cap).min(axis=1)      # +death/outcome downstream
    return cohort[["person_id", "index_date", "baseline_start", "censor_date"]]

Citations

FOUNDATIONAL / METHODS
  1. [1]Hernán MA, Robins JM. Using big data to emulate a target trial when a randomized trial is not available. American Journal of Epidemiology. 2016;183(8):758-764.
  2. [2]Benchimol EI, Smeeth L, Guttmann A, et al. The REporting of studies Conducted using Observational Routinely-collected health Data (RECORD) statement. PLoS Medicine. 2015;12(10):e1001885.
APPLIED EXAMPLES
  1. [3]Langan SM, Schmidt SAJ, Wing K, et al. The reporting of studies conducted using observational routinely collected health data statement for pharmacoepidemiology (RECORD-PE). BMJ. 2018;363:k3532.
REPORTING & GUIDANCE
  1. [4]Berger ML, Sox H, Willke RJ, et al. Good practices for real-world data studies of treatment and/or comparative effectiveness: recommendations from the joint ISPOR-ISPE Special Task Force on real-world evidence in health care decision making. Pharmacoepidemiology and Drug Safety. 2017;26(9):1033-1039.