← Methods repository
CONCEPTINTERMEDIATEPYTHON · R · SAS4 citations

Composite Endpoint Construction

The pre-specified rule that combines two or more component events (e.g., death, non-fatal MI, hospitalization) into a single outcome, defining each component's case definition, the event-date assignment (typically the earliest qualifying component), the deduplication window, and the analytic estimand (time-to-first-event, recurrent-event, hierarchical, or competing-risk) in real-world data.

Outcome Measurecomposite-endpointmacetime-to-first-eventwin-ratiocompeting-riskscomponent-ascertainmentoutcome-algorithm-construction
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 composite endpoint combines several serious health events — such as heart attack, stroke, and death — into a single outcome so that a study has enough events to detect a treatment effect. The rule is simple: a patient counts as having the outcome on the earliest date that any one of those events occurs, and follow-up stops there. Because the study records which specific event happened first, researchers can always go back and look at each event separately. One honest catch: if one event (say, a hospitalization) happens far more often than the others, it can dominate the result and make a treatment look effective even if it does nothing for the rarer but more serious events.

When to use it
Components are biologically linked, comparable in severity, and expected to move together; always report components individually alongside the composite.
Components are of similar severity and the conventional contrast is required; switch to win-ratio when a soft component dominates the count.
The single hard endpoint is under-powered and components are clinically linked; prefer the single endpoint when differential surveillance by arm is plausible.
Watch out for
Presumes components share treatment direction and clinical importance; a near-null composite can hide opposite-direction component effects.
Weights death and a soft hospitalization equally; a drug that prevents deaths but causes admissions is falsely penalized.
Vulnerable to differential ascertainment of soft components by arm and to inconsistent cross-study definitions.

A composite endpoint counts a patient as having "the outcome" when any one of several pre-specified component events occurs. The classic example is 3-point MACE (all-cause death + non-fatal myocardial infarction + non-fatal stroke). The default analytic representation is time-to-first-event: the composite event date is the earliest date among the patient's qualifying components, and follow-up is censored at that first event. The deceptively simple `MIN(component_date)` hides every hard decision — what each component's case definition is, how each component is ascertained (and how well), how same-window events are deduplicated, and which estimand the composite is meant to support.

Core conceptual / estimand distinction

The construction rule and the estimand are separable choices that must both be pre-specified, because they drive different models:

  • Time-to-first-event (default). Event = earliest component; analyze with cause-specific Cox or pooled logistic. Simple and the FDA/regulatory default, but it (a) discards all information after the first event, (b) weights a soft component (e.g., hospitalization) exactly the same as death, and (c) lets a frequent, low-severity, well-ascertained component dominate the hazard ratio while a rare, high-severity component drives clinical meaning.
  • Recurrent / total events (Andersen–Gill, LWYY, negative-binomial). Counts all qualifying events per patient, not just the first — appropriate when repeated hospitalizations carry information (e.g., heart-failure burden).
  • Hierarchical / win-ratio (Pocock 2011) and restricted-mean approaches. Compare patients pairwise on the most severe component first, breaking ties on the next, so death is never outweighed by a hospitalization. Respects clinical priority at the cost of an unfamiliar effect measure (win ratio) and no single survival curve.
  • Cumulative incidence with death as a competing risk. If a non-fatal component is the endpoint of interest and death competes, the cause-specific hazard answers a different question than the subdistribution (Fine–Gray) cumulative incidence. Naively treating death as censoring overstates the non-fatal component's cumulative incidence.

Two operational invariants make all of this auditable: retain the composite event date AND the component identifier that produced it. Every component-level sensitivity analysis, every "which piece drove the effect" question, and every competing-risk re-analysis depends on knowing which component fired and when.

Pros, cons, and trade-offs

  • vs analyzing each component separately: A composite raises event counts and statistical power, shortens required follow-up, and side-steps the multiplicity of testing several outcomes. Cost: it presumes the components share a common treatment effect and similar clinical importance — assumptions that are false more often than not (Freemantle 2003; Ferreira-González 2007). Prefer the composite only when components are biologically linked, of comparable severity, and expected to move in the same direction; always report the components individually alongside it.
  • vs hierarchical / win-ratio analysis: Time-to-first-event is universally understood and maps to a hazard ratio and a Kaplan–Meier curve. The win ratio (Pocock 2011) preserves the severity ordering death > MI > hospitalization, so a drug that prevents deaths but causes extra admissions is not falsely rewarded. Prefer the win ratio / hierarchical estimand when components differ sharply in severity or when a soft component dominates the count; prefer time-to-first-event when components are of similar importance and regulators expect the conventional contrast.
  • vs a single hard outcome (e.g., all-cause mortality): A single hard endpoint is unambiguous, maximally ascertainable from death indices, and immune to differential surveillance — but is often under-powered. The composite trades that cleanliness for power. Prefer the single hard endpoint when it is adequately powered and when differential ascertainment of soft components by arm is plausible.

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

  • Components have opposing or markedly heterogeneous expected effects. If a drug plausibly lowers MI but raises hospitalization, the composite hazard ratio can hover near the null while masking real, opposite-direction component effects. Require pre-specified, plausible per-component effect estimates before trusting any composite (Freemantle 2003).
  • A soft, frequent component dominates the count but a hard component drives clinical meaning. When 80% of composite events are hospitalizations and 5% are deaths, the "significant" composite is essentially a hospitalization study wearing a mortality costume. Always tabulate the component breakdown.
  • Differential ascertainment by arm. Composite event date = `MIN(component_date)`, so the best-ascertained component systematically wins the event-date assignment. If one arm has more healthcare contact (e.g., a drug requiring frequent labs or monitoring visits), its non-fatal, encounter-dependent components are detected earlier and more often — inflating its composite rate for reasons that have nothing to do with biology. This is the dominant RWE-specific failure mode.
  • Cross-study comparison with inconsistent definitions. 3-point vs 4-point vs 5-point MACE, or different ICD code lists and code-position rules, are not interchangeable; pooling or comparing them is comparing different outcomes.
  • Death as a component AND a subdistribution interpretation for a non-fatal piece. You cannot coherently treat death as both part of the composite and a competing risk for a sub-component in the same framing — pick one estimand.

Data-source operational depth

  • Claims (FFS): Each component is an algorithm with its own validity. All-cause death is near-complete only when linked to SSA Master Death File / NDI (claims-based death proxies — e.g., discharge status, enrollment termination — miss out-of-hospital deaths). Non-fatal MI and stroke are ICD-10-CM algorithms whose PPV depends on code position (primary inpatient diagnosis ≈ high PPV; any-position or outpatient ≈ low PPV) and whether a `1 inpatient OR 2 outpatient` rule is applied. Failure modes: (a) acute-event re-coding — a single MI generates an index hospitalization, a transfer, and follow-up outpatient claims; without a deduplication / clean window these become spurious "recurrent" events; (b) adjudication/claims lag — late-arriving claims shift event dates and can move an event across the end-of-data boundary; (c) differential surveillance by arm as above.
  • Medicare Advantage-only person-time: Encounter (non-fatal) claims are frequently incomplete or absent, while death is still captured via linked mortality. The composite therefore degrades into a near-death-only outcome in MA segments — silently changing the estimand by enrollment type. Restrict to FFS Parts A/B (and D for exposure) for the components that rely on medical claims, or model enrollment type explicitly.
  • EHR: Non-fatal components come from problem lists, encounter diagnoses, labs, and notes; capture is visit-driven, so a patient who seeks care outside the system has events that simply never appear (external-care leakage). Death is notoriously incomplete in EHR alone — link to a death index. EHR can sharpen a component definition (troponin for MI, imaging for stroke) where claims cannot.
  • Registry / linked: Registries often provide adjudicated components (the gold standard for the composite's clinical pieces) but weak longitudinal completeness; link to claims for full follow-up and to a death index for the mortality component. Linkage introduces selection (only the linkable subset) and date-discrepancy issues (claim service date vs adjudicated event date) that must be reconciled before assigning the composite event date.

Worked claims example

Endpoint: 3-point MACE (all-cause death + non-fatal MI + non-fatal stroke) in an SGLT2-inhibitor vs DPP-4-inhibitor active-comparator new-user study in a commercial + Medicare FFS database with linked mortality.

  1. Component case definitions. Non-fatal MI = an inpatient claim with ICD-10-CM `I21.x` in the primary position (high-PPV rule; pre-specify a sensitivity analysis using any-position). Non-fatal stroke = inpatient `I63.x` primary. Death = earliest date across the mortality source hierarchy (linked SSA/NDI date, then inpatient discharge status = expired, then enrollment-termination-for-death) — never a claims proxy alone.
  2. Continuous enrollment + washout. Require 365 days of continuous FFS A/B (and D for the exposure) before `index_date`; restrict component ascertainment to FFS person-time so MA gaps do not silently drop non-fatal events.
  3. Deduplication / clean window. An inpatient MI plus a transfer and two follow-up office visits coded I21 within 30 days is one MI — collapse component claims within a pre-specified acute-event window to the admission date.
  4. Event-date assignment. Composite event date = earliest qualifying component date; store both the date and the component label. Edge case: a stroke claim dated three days before a death date — if the death is the index hospitalization's terminal event, count it as a single composite event at the stroke date with component = "non-fatal stroke then death" flagged; the time-to-first-event estimand counts only the first, but the component flag preserves the death for the competing-risk re-analysis.
  5. Follow-up & censoring. From `index_date` to the composite event date, censoring at disenrollment, end of data, and (for as-treated) discontinuation.
  6. Analysis & sensitivity. Primary = cause-specific Cox for time-to-first MACE; report the component breakdown (how many deaths vs MI vs stroke), a Fine–Gray cumulative-incidence analysis when a single non-fatal component is examined with death as a competing risk, the win-ratio as a severity-weighted alternative, and re-runs under the any-position MI rule and an alternative deduplication window.

Interpreting the output

. In the Patient 7741 example, an MI claim in principal position appears on day 100 from index; a stroke claim appears on day 204 and a death record on day 289. The composite-endpoint algorithm fires on day 100 and labels the event component as "non-fatal MI." Stroke and death are not counted as additional composite events — only the first qualifying component triggers the time-to-event clock.

Formal interpretation: the composite event date is day 100, and the component label is non-fatal MI. The hazard ratio estimated from this composite endpoint applies to the composite (MI, stroke, or death occurring first) — it does not apply to MI alone, stroke alone, or death alone. This is a consequential restriction: a treatment that prevents MI but shifts events toward stroke will produce a composite HR near 1.0 even though the clinical picture changed substantially. The composite is driven by whichever component accumulates events most rapidly, often the softest (most frequently occurring) component; if most composite events are MI and few are stroke or death, the composite HR is essentially an MI HR, and calling it a "MACE" estimate is misleading.

Practical interpretation: always report the component breakdown — number and proportion of composite events attributable to each component — alongside the primary composite HR. If one component dominates, pre-specify component-specific analyses and consider whether the composite still addresses the clinical question. The win-ratio analysis, which weights events by clinical severity, is a useful pre-specified sensitivity analysis when component heterogeneity is anticipated.

Decision diagram

flowchart TD
  Comp[Per-component case definitions<br/>DEATH / MI / STROKE<br/>each with its own PPV + code-position rule] --> Dedup[Deduplicate same-component<br/>acute episodes within clean window]
  Dedup --> Min[Composite event = EARLIEST component date<br/>store date AND winning component label]
  Min --> Estimand{Estimand?}
  Estimand -->|components similar severity| TTE[Time-to-first-event<br/>cause-specific Cox / pooled logistic]
  Estimand -->|severity differs| Win[Hierarchical / win-ratio<br/>death before hospitalization]
  Estimand -->|non-fatal piece, death competes| FG[Fine-Gray subdistribution<br/>+ cause-specific hazard]
  Estimand -->|repeated events matter| Rec[Recurrent events<br/>Andersen-Gill / LWYY]
  TTE --> Report[Always report component breakdown<br/>+ sensitivity on code-position and dedup window]
  Win --> Report
  FG --> Report
  Rec --> Report
From per-component case definitions to the composite event date to the estimand. The earliest-component rule means the best-ascertained component tends to win the event-date assignment, so component-level validation and the component breakdown are mandatory diagnostics.
gantt
  title One patient's component events and the composite event date (claims)
  dateFormat YYYY-MM-DD
  axisFormat %b %Y
  section Follow-up
  Index date -> follow-up start :milestone, idx, 2024-01-01, 0d
  section Components
  Non-fatal MI (I21 primary, inpatient) :crit, mi, 2024-04-10, 1d
  Stroke claim (within MI clean window -> deduped) :done, st, 2024-04-25, 1d
  Death (linked mortality) :active, dth, 2024-09-15, 1d
  section Composite
  Composite event = earliest = MI; component label retained :milestone, comp, 2024-04-10, 0d
Time-to-first-event assignment for one patient. The MI is the earliest qualifying component, so the composite event date is the MI date and follow-up is censored there; the death is preserved as a component flag for the competing-risk re-analysis even though it does not count first.

Worked example

Scenario

Margaret is a 68-year-old Medicare patient enrolled in an SGLT2-inhibitor study. Her index date — the day she fills her first prescription — is January 1, 2024. Researchers are tracking 3-point MACE: non-fatal heart attack (MI), non-fatal stroke, or death from any cause, whichever comes first. They follow Margaret until one of those events happens, she loses insurance coverage, or the data end on December 31, 2024. She experiences all three component events during the year, but only the earliest one defines her composite endpoint.

Dataset

Component-event claims for one patient (Margaret, person_id 7741). Each row is a qualifying event that passed its own code-based case definition — inpatient primary-diagnosis code for MI and stroke, linked mortality file for death.

person_idevent_datecomponentsource
77412024-04-10MIinpatient claim, I21.9 primary
77412024-07-22STROKEinpatient claim, I63.9 primary
77412024-10-15DEATHlinked mortality file
FIG. 1 — DESIGN TIMELINE
A horizontal timeline from January 1 to December 31 2024 for one patient. The index date anchors the left end. A marker labeled 'MI day 100' on April 10 is flagged as the composite trigger. A marker labeled 'Stroke day 204' on July 22 and a marker labeled 'Death day 289' on October 15 appear to the right but are shown as inactive because follow-up closed at day 100. A shaded span from January 1 to April 10 is labeled 'Active follow-up: 100 days'.
Margaret's three component events are shown on the timeline. The heart attack (MI) on April 10 is the earliest — it fires the composite endpoint on day 100 and closes her follow-up. The stroke (day 204) and death (day 289) appear on the diagram to show they happened, but they do not change the composite result because follow-up stopped at the first event.

Steps

1Start the clock at Margaret's index date: January 1, 2024 (day 0).
2List every qualifying component event inside her follow-up window, with the date it occurred: MI on April 10 (day 100), stroke on July 22 (day 204), death on October 15 (day 289).
3Apply the earliest-event rule: composite event date = the minimum of {April 10, July 22, October 15} = April 10.
4Margaret's composite outcome is recorded as: event = 1 (yes, she had the composite), time_to_composite = 100 days, composite_component = 'MI'.
5Follow-up is stopped at day 100 — the stroke and death still happened, but they occur after the composite has already fired and are not counted in a time-to-first-event analysis.
6The composite_component label 'MI' is kept alongside the date so analysts can later ask 'how many composite events were MIs vs strokes vs deaths?' and run sensitivity analyses on each component separately.

Result

Composite endpoint = MI; time-to-composite = 100 days (April 10, 2024). The stroke (day 204) and death (day 289) occurred after the composite fired and do not alter the primary outcome — though the component label stored with the record makes them available for secondary analyses.

Trade-offs

vs. Analyzing each component as a separate outcome
Pros of this
Higher event counts and power, shorter required follow-up, avoids multiplicity across several outcomes.
vs. Hierarchical / win ratio analysis
Pros of this
Time-to-first-event yields a familiar hazard ratio and Kaplan-Meier curve that regulators expect.
vs. A single hard endpoint (e.g., all cause mortality)
Pros of this
Power and shorter follow-up from combining events.

Runnable example

Derive a time-to-first-event composite from claims-style component events. Required inputs (already cleaned and mapped to component case definitions upstream): cohort : one row per patient -> person_id, index_date (datetime), fu_end (datetime: min of disenroll/death/data end) comp_events: one row per qualifying...

requires: pandas · numpy
import pandas as pd
import numpy as np

DEDUP_DAYS = 30  # acute-event clean window: claims of the SAME component within this window = one event

def build_composite(cohort: pd.DataFrame, comp_events: pd.DataFrame) -> pd.DataFrame:
    ev = comp_events.merge(cohort[["person_id", "index_date", "fu_end"]], on="person_id")

    # Keep only component events inside each patient's follow-up window.
    ev = ev[(ev["event_date"] > ev["index_date"]) & (ev["event_date"] <= ev["fu_end"])]

    # Deduplicate same-component acute episodes: a claim opens a new episode only if it falls more than
    # DEDUP_DAYS after the LAST KEPT episode date (anchored, not chained off the immediately prior claim),
    # matching the SAS step and the acute-event-deduplication-window concept.
    ev = ev.sort_values(["person_id", "component", "event_date"])

    def _keep_anchored(dates: pd.Series) -> pd.Series:
        keep, last = [], None
        for d in dates:
            if last is None or (d - last).days > DEDUP_DAYS:
                keep.append(True); last = d
            else:
                keep.append(False)
        return pd.Series(keep, index=dates.index)

    new_episode = ev.groupby(["person_id", "component"])["event_date"].transform(_keep_anchored)
    ev = ev[new_episode]

    # Composite event = earliest qualifying component; preserve WHICH component fired.
    ev = ev.sort_values(["person_id", "event_date"])
    first = ev.groupby("person_id").first().reset_index()
    first = first.rename(columns={"event_date": "composite_date", "component": "composite_component"})

    out = cohort.merge(first[["person_id", "composite_date", "composite_component"]], on="person_id", how="left")
    out["event"] = out["composite_date"].notna().astype(int)
    # Time = composite event date if it occurred, else censoring at follow-up end.
    end = out["composite_date"].fillna(out["fu_end"])
    out["time_days"] = (end - out["index_date"]).dt.days
    return out[["person_id", "index_date", "time_days", "event", "composite_component"]]

Citations

FOUNDATIONAL / METHODS
  1. [1]Freemantle N, Calvert M, Wood J, Eastaugh J, Griffin C. Composite outcomes in randomized trials: greater precision but with greater uncertainty? JAMA. 2003;289(19):2554-2559.
  2. [2]Cordoba G, Schwartz L, Woloshin S, Bae H, Gøtzsche PC. Definition, reporting, and interpretation of composite outcomes in clinical trials: systematic review. BMJ. 2010;340:c3920.
  3. [3]Ferreira-González I, Permanyer-Miralda G, Domingo-Salvany A, et al. Problems with use of composite end points in cardiovascular trials: systematic review of randomised controlled trials. BMJ. 2007;334(7597):786.
APPLIED EXAMPLES
  1. [4]Pocock SJ, Ariti CA, Collier TJ, Wang D. The win ratio: a new approach to the analysis of composite endpoints in clinical trials based on clinical priorities. European Heart Journal. 2012;33(2):176-182.