Inpatient Bridging of Drug Exposure
A pre-specified rule that decides how to treat days during a hospital stay when outpatient pharmacy fills are absent or suspended, when constructing exposure episodes and adherence/persistence measures from claims or linked data.
In plain language
When a patient is hospitalized, the hospital supplies their medication directly — no prescription gets filled at a pharmacy, so no record of those days shows up in outpatient claims data. Naively stitching prescription fills together makes the hospital stay look like a gap in drug coverage, even though the patient never actually stopped taking the medication. Inpatient bridging is a pre-specified rule that says: during a confirmed hospital stay, treat the patient as still covered by their chronic medication rather than calling those days a gap. Without this rule, a patient who was faithfully taking a heart medication through a two-week admission can be mislabeled 'non-adherent' purely because the data source cannot see inside the hospital.
Inpatient bridging
is the explicit, protocol-level decision about what an exposure series should assume during the days a patient is hospitalized. In outpatient pharmacy claims, exposure is reconstructed by stitching together fills (`fill_date` + `days_supply`). During an inpatient stay the patient typically receives medication from the hospital formulary, so there is no outpatient fill — and in claims-only data the inpatient drug is bundled into the DRG/facility payment and is therefore invisible. The series shows an apparent gap that is an artifact of where the drug was sourced, not evidence the patient stopped therapy. How that gap is handled changes denominators, exposure time, gap counts, and every downstream measure (PDC, MPR, persistence, time-varying exposure). This is an `Exposure_Definition` problem, not an estimation problem: the choice is made in the cohort/episode build, before any model.
Core conceptual distinction
There are three canonical bridging policies, and they are mutually exclusive choices that must be named in the protocol: 1. Carry-over (assume continuation): treat inpatient days as covered/exposed — bridge across the stay as if the drug continued. Rationale: an inpatient who was on chronic therapy is overwhelmingly likely to have it continued in hospital. This is the most common default for chronic maintenance drugs. 2. Censor (remove inpatient days from the denominator): exclude hospitalized days from the observation window entirely, so they count as neither covered nor uncovered. This is the PQA / CMS Star Ratings convention for adherence PDC: inpatient and skilled-nursing days are removed from the denominator and any overlapping supply is "pushed back," because the member's outpatient adherence cannot be observed during institutional stays. 3. Treat as gap / discontinuation: count inpatient days as uncovered (a true gap), or end the exposure episode at admission. Appropriate only when the drug is genuinely not expected to continue (e.g., a therapy held for the procedure, a discontinued agent). The estimand-adjacent point: these three policies are not nuances — for a patient with frequent or long admissions they produce materially different PDC and persistence values, and the "right" choice depends on the clinical expectation for that specific drug during that specific kind of stay.
Pros, cons, and trade-offs
(vs the named alternatives): - Carry-over vs censor: Carry-over is simple and matches the clinical reality for chronic drugs, but it manufactures coverage you did not observe and can mask true non-adherence around discharge. Censoring (PQA-style) is the most defensible when the question is observable outpatient adherence and is required for Star Ratings comparability, but it shrinks the denominator, can inflate PDC for frequently hospitalized (sicker) patients, and complicates person-time accounting. Prefer carry-over for chronic maintenance therapy in an etiologic study; prefer censor for regulated quality measurement and when inpatient supply is unknowable. - Carry-over vs treat-as-gap: Treat-as-gap is correct only for drugs plausibly held during the stay; applied to a chronic drug it invents discontinuations and biases persistence downward. Prefer treat-as-gap only with a clinical rationale, ideally validated against linked MAR/eMAR data. - vs ignoring the issue (naive stitching): Doing nothing silently applies whatever the default `days_supply` arithmetic produces — usually a phantom gap. That is the worst option because the policy is implicit and undocumented. Any of the three explicit policies beats an unstated one.
When to use
Whenever exposure episodes, PDC/MPR, persistence, or time-varying exposure are built from outpatient pharmacy claims in a population that is hospitalized at non-trivial rates (elderly, oncology, cardiovascular, dialysis, transplant, serious mental illness). It is mandatory to specify a bridging rule for any chronic-disease adherence or comparative-effectiveness study and for any regulated PDC measure.
When NOT to use — and when it is actively misleading or dangerous
Bridging is unnecessary when admissions are rare and short relative to the supply and outcome window (the choice cannot move the estimate). It becomes actively dangerous in three situations. (1) Asymmetric application — bridging one arm (or only the study drug) but not the comparator manufactures immortal time and covered person-time for one side, biasing the comparative estimate; the rule must be applied identically to both arms (see immortal-time-bias-handling). (2) Differential hospitalization by arm — if the sicker arm is hospitalized more, a carry-over policy donates more phantom coverage to that arm, while a censoring policy removes more of its observable time; either way the policy choice becomes outcome-dependent, so a sensitivity analysis across all three policies is not optional. (3) Treating-as-gap a drug that was actually continued in hospital — fabricates discontinuations, corrupts persistence, and (in claims-only data, where you cannot see the inpatient administration) is unfalsifiable without linkage.
Data-source operational depth
- Claims (FFS): Identify inpatient stays from institutional/facility claims (revenue center codes, place-of-service, DRG, admit/discharge dates). The inpatient drug is bundled into the facility payment and never appears as an NDC, so you must infer coverage from the stay dates plus the surrounding outpatient fills. Reconstruct admission and discharge from the medical claim, then apply the chosen policy to `[admit_date, discharge_date]`. Failure mode: over-the-counter or sample inpatient continuation is invisible; same-day discharge fills and discharge-prescription "med rec" fills can double-count if not deduped. - Claims (Medicare Advantage / capitated): MA encounter data are notoriously incomplete and lag; an MA-only person may have neither the institutional claim nor reliable Part D fills, so "no fill during a window" can be pure missingness rather than a real gap or a real stay. Restrict to FFS Parts A/B/D person-time, or flag MA-only spans and exclude them from the denominator — do not let MA missingness masquerade as non-adherence. - EHR: The inpatient administration is visible in the MAR/eMAR and inpatient order records, so bridging can be evidence-based rather than assumed — but only if the hospital is inside the EHR network. External-hospital stays leak out of the system and reappear as the same phantom gap as in claims; visit-driven capture means the patient who is admitted elsewhere is differentially unobserved. - Registry: Usually weak for both fills and inpatient drug administration; use registry admission/severity fields to flag stays, but link to claims (fills) and to facility claims (stay dates) to actually operationalize the rule. - Linked claims–EHR: The ideal substrate — facility claims give reliable stay dates and the linked inpatient MAR confirms whether the specific drug was continued, letting you choose carry-over vs treat-as-gap per stay on evidence rather than assumption. Cost: only the linkable subset is covered, and admit/fill/service date discrepancies must be reconciled before bridging.
Worked claims example
A patient on a chronic statin fills a 30-day supply on 2024-01-01 (covers 2024-01-01 → 2024-01-30). A facility claim shows an inpatient stay 2024-01-11 → 2024-01-20 (10 days). The next outpatient fill (30 days) is 2024-02-05. The follow-up window is the 35 days 2024-01-01 → 2024-02-04. Compute PDC under each policy: - Carry-over: the in-hospital days are assumed covered. Covered days = Jan 1–30 (30 from the first fill, with the admission spanned) → no gap is recognized during the stay; the only uncovered days are Jan 31 → Feb 4 (5 days). PDC = 30 / 35 ≈ 0.857. - Censor (PQA): remove the 10 inpatient days from the denominator (Jan 11–20). Denominator = 35 − 10 = 25 days; covered observable days = Jan 1–10 (10) + Jan 21–30 (10) = 20. PDC = 20 / 25 = 0.800. (PQA additionally "pushes back" supply that overlapped the removed days, which can recover days near discharge; the directional point — a different denominator — holds.) - Treat-as-gap: the 10 inpatient days are uncovered. Covered = Jan 1–10 (10) + Jan 21–30 (10) = 20 over a 35-day denominator → PDC = 20 / 35 ≈ 0.571. Same patient, same fills: PDC ranges 0.571 → 0.857 — straddling the 0.80 quality-measure threshold — purely from the bridging rule. That single decision can flip a patient from "non-adherent" to "adherent," which is why the policy must be pre-specified, applied identically across arms, and stress-tested in sensitivity analysis.
Worked example
Scenario
Maria, age 68, has been taking a daily statin for high cholesterol for years. We are studying her medication coverage over a 60-day window from January 2 through March 1, 2024. She fills a 14-day supply on January 2, then is admitted to the hospital on January 10 and discharged on January 29 (a 20-day stay). The hospital keeps her on the statin the entire time, but no outpatient pharmacy claim is generated — the drug comes from the hospital's own supply. Her next outpatient fill is a 30-day supply on February 1. We want to compute how many days she actually had the drug during the 60-day window, and we will compare the naive (no-bridging) result to the carry-over-bridging result.
Dataset
Raw outpatient pharmacy fills — these are the only pill records visible without bridging. The hospital stay appears only in a separate facility claim (bottom table).
| person_id | fill_date | drug | days_supply |
|---|---|---|---|
| 2001 | 2024-01-02 | atorvastatin | 14 |
| 2001 | 2024-02-01 | atorvastatin | 30 |
Steps
Step 1 — Mark the observation window. We are watching Maria from January 2 through March 1, 2024. That is 60 days total (30 days in January starting Jan 2, 29 days in February — 2024 is a leap year, and March 1).
Step 2 — Map Fill A. The January 2 fill has a 14-day supply, so it covers January 2 through January 15 (14 days).
Step 3 — Map Fill B. The February 1 fill has a 30-day supply, so it covers February 1 through March 1 (30 days — all inside the window).
Step 4 — Naive calculation (no bridging). We only see the two pharmacy fills. Covered days = January 2–15 (14 days) + February 1–March 1 (30 days) = 44 covered days. The stretch January 16 through January 31 (16 days) looks like an uncovered gap. Naive PDC = 44 / 60 = 0.733.
Step 5 — Identify the hospital stay. The facility claim shows Maria was admitted January 10 and discharged January 29 — a 20-day inpatient stay. No outpatient fill was generated during those days because the hospital dispensed the statin itself.
Step 6 — Apply carry-over bridging. We treat the 20 hospital days (January 10–29) as covered, just as if she had a pill in her hand each day. Now combine: Fill A covers January 2–15, and the bridge extends coverage through January 29. The union of these two is January 2–29 = 28 covered days.
Step 7 — Identify the true gap. After discharge on January 29, the next outpatient fill is February 1. The two days January 30–31 are genuinely uncovered — she is home, out of the hospital, and has not yet refilled.
Step 8 — Compute bridged PDC. Covered days = January 2–29 (28 days) + February 1–March 1 (30 days) = 58 covered days. Bridged PDC = 58 / 60 = 0.967.
Step 9 — Compare. Without bridging: PDC = 0.733 — Maria looks non-adherent by the common 0.80 threshold. With carry-over bridging: PDC = 0.967 — she is highly adherent. The 16-day apparent gap shrinks to a 2-day real gap. The difference is entirely explained by where the drug was sourced, not by whether she actually took it.
Result
Naive PDC (no bridging) = 44 covered days / 60 window days = 0.733 — below the 0.80 adherence threshold. Bridged PDC (carry-over) = 58 covered days / 60 window days = 0.967 — well above the threshold. The single decision to bridge the 20-day hospital stay adds 14 covered days (the inpatient days beyond Fill A's supply) and eliminates a phantom gap, moving Maria from 'non-adherent' to 'highly adherent'.
Inpatient Claim
Facility (inpatient) claim for the same patient — the hospital stay visible here, but no drug NDC appears because the drug cost is bundled into the hospital bill.
| person_id | admit_date | discharge_date | stay_days |
|---|---|---|---|
| 2001 | 2024-01-10 | 2024-01-29 | 20 |
Timeline Spec
- Title
Inpatient bridging: 60-day statin coverage with a 20-day hospital stay (patient 2001)
- Window
- Start
2024-01-02
- End
2024-03-01
- Label
Denominator: 60-day observation window (Jan 2 – Mar 1, 2024)
- Events
- Label
Fill A
- Start
2024-01-02
- Length Days
14
- Quantity
14-day supply
- Label
Inpatient stay (no outpatient fill — hospital supplies the drug)
- Start
2024-01-10
- Length Days
20
- Quantity
20-day stay
- Label
Fill B
- Start
2024-02-01
- Length Days
30
- Quantity
30-day supply
- Spans
- Kind
covered
- Start
2024-01-02
- End
2024-01-15
- Label
Fill A: 14 covered days (outpatient)
- Kind
exposed
- Start
2024-01-10
- End
2024-01-29
- Label
Hospital stay: drug supplied by facility — no outpatient claim generated
- Kind
gap
- Start
2024-01-16
- End
2024-01-31
- Label
Naive view: 16-day apparent gap (Jan 16–31) — includes 14 inpatient days + 2 post-discharge days
- Kind
covered
- Start
2024-01-10
- End
2024-01-29
- Label
Bridged view: inpatient days treated as covered (carry-over rule)
- Kind
gap
- Start
2024-01-30
- End
2024-01-31
- Label
True gap after bridging: 2 days (Jan 30–31, post-discharge before refill)
- Kind
covered
- Start
2024-02-01
- End
2024-03-01
- Label
Fill B: 30 covered days (outpatient)
- Result
- Label
Naive PDC = 44/60 = 0.733 (non-adherent) → Bridged PDC = 58/60 = 0.967 (adherent). Bridge adds 14 inpatient days beyond Fill A, shrinking the apparent 16-day gap to a true 2-day gap.
- Value
0.967
- Caption
Maria's statin coverage over 60 days. Fill A (14 days) runs out January 15; her hospital admission (January 10–29) falls partly within Fill A and extends 14 days beyond it with no outpatient pharmacy record. Without bridging, January 16–31 looks like a 16-day gap and PDC = 0.733. With carry-over bridging (hospital days assumed covered), coverage extends through January 29, the true gap shrinks to 2 days, and PDC = 0.967 — straddling the 0.80 adherence threshold purely based on the bridging rule.
- Alt Text
Horizontal timeline from January 2 to March 1, 2024, showing two pharmacy fill bars (Fill A: 14 days starting Jan 2; Fill B: 30 days starting Feb 1), a 20-day hospital stay bar (Jan 10–29), a wide apparent-gap shading under the naive view (Jan 16–31), a bridged-coverage overlay spanning Jan 10–29, and a small true-gap shading (Jan 30–31). Two PDC result labels: Naive 0.733 and Bridged 0.967.
Runnable example
python implementation
Apply a bridging policy to outpatient exposure days. Required inputs (cleaned, deduped): fills : person_id, fill_date (datetime), days_supply (int) stays : person_id, admit_date (datetime), discharge_date (datetime) # from facility/institutional claims...
import pandas as pd
import numpy as np
def _covered_dates(fills: pd.DataFrame) -> set:
# Days covered by outpatient supply: each fill covers [fill_date, fill_date + days_supply - 1].
out = set()
for _, r in fills.iterrows():
out.update(pd.date_range(r["fill_date"],
r["fill_date"] + pd.Timedelta(days=int(r["days_supply"]) - 1)))
return out
def _inpatient_dates(stays: pd.DataFrame) -> set:
out = set()
for _, r in stays.iterrows():
out.update(pd.date_range(r["admit_date"], r["discharge_date"]))
return out
def pdc_with_bridging(fills, stays, obs_start, obs_end, policy="carryover") -> float:
window = set(pd.date_range(obs_start, obs_end))
inpatient = _inpatient_dates(stays) & window
covered = _covered_dates(fills) & window
if policy == "carryover":
covered = covered | inpatient # assume the drug continued in hospital
denom = window
elif policy == "censor":
covered = covered - inpatient # inpatient days observable for neither num nor denom
denom = window - inpatient # PQA: remove institutional days from the denominator
elif policy == "gap":
covered = covered - inpatient # inpatient days count as uncovered
denom = window
else:
raise ValueError(f"unknown policy: {policy}")
return len(covered & denom) / len(denom) if denom else np.nanr implementation
Apply a bridging policy to outpatient exposure days with data.table. Inputs mirror the Python version: fills : person_id, fill_date (Date), days_supply (integer) stays : person_id, admit_date (Date), discharge_date (Date) Returns PDC for one person under...
library(data.table)
covered_days <- function(fills) {
# Each fill covers fill_date .. fill_date + days_supply - 1.
unique(do.call(c, Map(function(d, n) seq(d, d + n - 1L, by = "day"),
fills$fill_date, as.integer(fills$days_supply))))
}
inpatient_days <- function(stays) {
unique(do.call(c, Map(function(a, b) seq(a, b, by = "day"),
stays$admit_date, stays$discharge_date)))
}
pdc_with_bridging <- function(fills, stays, obs_start, obs_end, policy = "carryover") {
window <- seq(obs_start, obs_end, by = "day")
inpatient <- intersect(inpatient_days(stays), window)
covered <- intersect(covered_days(fills), window)
if (policy == "carryover") { # assume continuation in hospital
covered <- union(covered, inpatient); denom <- window
} else if (policy == "censor") { # PQA: drop institutional days from denominator
covered <- setdiff(covered, inpatient); denom <- setdiff(window, inpatient)
} else if (policy == "gap") { # inpatient days count as uncovered
covered <- setdiff(covered, inpatient); denom <- window
} else stop("unknown policy")
if (length(denom) == 0L) return(NA_real_)
length(intersect(covered, denom)) / length(denom)
}