Dose-Response and Exposure-Response Modeling in RWE
Models the shape of the relationship between a treatment amount or exposure metric and an outcome, using real-world dose, cumulative exposure, adherence, therapeutic drug monitoring, or linked PK/PD proxies while separating pharmacologic signal from confounding by indication, titration, tolerability, and outcome-driven dose changes.
In plain language
Dose-response modeling asks whether more exposure to a treatment is linked to more benefit or more harm. In real-world data, "dose" may mean the strength dispensed at the pharmacy, cumulative milligrams over time, an administered biologic dose, or a measured drug level. The hard part is that patients do not receive higher or lower doses randomly, so the curve must be designed around titration, frailty, tolerance, disease severity, and survival long enough to accumulate dose.
Dose-response and exposure-response modeling
asks whether more treatment produces more benefit, more harm, a plateau, a threshold, or a U/J-shaped curve. In RWE the exposure axis is rarely the clean randomized dose used in a phase 2 trial. It may be the dispensed strength on the index fill, average daily dose reconstructed from `fill_date` and `days_supply`, cumulative mg, dose intensity during an as-treated episode, therapeutic drug monitoring concentration, or a biologic-administration dose from medical claims. The analyst must state which axis is being modeled because a "dose-response" curve based on prescribed dose and an "exposure-response" curve based on observed concentration answer different questions.
Core conceptual distinction
A dose curve in routine care is not automatically causal. Higher dose often marks worse baseline disease, better tolerance, larger body size, renal function, prescriber practice, insurance access, or survival long enough to titrate. Lower dose can mark frailty, toxicity, contraindications, or early non-response. The curve therefore combines pharmacology with clinical selection unless time zero, dose construction, confounder timing, and post-baseline dose changes are handled explicitly. The deliverable is the predicted risk, rate, mean response, or marginal effect over the observed exposure range with a declared reference exposure, not the individual spline or Emax coefficients.
Pros, cons, and trade-offs
- Dispensed dose vs observed exposure. Claims-based dose is available at scale and maps to label strengths, but it does not prove ingestion or biologic exposure. Concentration or biomarker exposure is closer to pharmacology but usually exists only in EHR/registry subsets and is measured when clinicians are worried, creating informative observation. - Continuous curve vs dose categories. A restricted cubic spline, Emax, or MCP-Mod-style model preserves ordering and can reveal plateaus or thresholds. Categories are easier to explain to a payer but throw away within-category information and can invent false thresholds. Prefer a curve as the primary analysis and evaluate it at clinically recognizable dose anchors for reporting. - Baseline dose vs time-updated dose. Baseline dose avoids feedback from early outcomes but misses titration and dose reductions. Time-updated dose follows real exposure but can condition on intermediate response, toxicity, or survival. Use marginal structural or clone-censor-weight logic when dose changes are themselves treatment strategies. - Parametric pharmacology vs flexible regression. Emax and sigmoid Emax encode a plateau and are useful when pharmacology supports that shape. Splines are safer when the shape is unknown, but they extrapolate poorly and require enough events across the dose range.
When to use
Use this concept when the question is about the exposure-response shape rather than a simple treated-vs-comparator contrast: dose finding from routine care, comparing label strengths, estimating cumulative-dose harm, evaluating dose-intensity loss after interruptions, checking whether a safety signal rises monotonically with cumulative exposure, or translating therapeutic drug monitoring into clinical risk. It is most defensible when dose was assigned or changed for reasons observable before the dose interval, the dataset captures enough dose range, and the outcome is measured similarly across dose levels.
When NOT to use - and when it is actively misleading
- Do not interpret an observed high-dose vs low-dose association as pharmacologic unless severity, renal function, prior response, body size, route, prescriber, and access are measured before the dose decision. - Do not define "high cumulative dose" using future follow-up without a design that prevents immortal time. Patients must survive and remain observable to accumulate dose. - Do not adjust for post-index biomarkers, adherence, or monitoring visits as ordinary confounders if they are consequences of earlier dose or early response. - Do not extrapolate beyond observed doses. RWE dose curves are descriptive or causal only over the support of real patients who received those doses.
Data-source operational depth
Claims data support large dose analyses when NDC strength, quantity, days supply, medical J-codes, and enrollment are complete; they are weak for actual ingestion, inpatient administrations, dose samples, and weight-based biologic dosing unless medical and pharmacy benefits are linked. EHR data add weight, renal function, labs, and sometimes administered dose or therapeutic drug monitoring, but measurements are visit-driven and often ordered because of toxicity or non-response. Registries add disease severity and adjudicated outcomes but may miss complete pharmacy fills. Linked claims-EHR-vital-records is strongest, but the linked subset is selected and order, fill, administration, and lab dates must be reconciled before constructing the exposure axis.
Worked example
Scenario
A claims-EHR study evaluates whether higher semaglutide dose is associated with larger one-year HbA1c reduction among adults with type 2 diabetes. Pharmacy claims identify dispensed dose strengths and days supply. EHR labs provide baseline and follow-up HbA1c. The analyst wants a curve, not just a high-dose vs low-dose comparison.
Dataset
Illustrative dose strata after constructing average daily dose during the first 180 days and requiring baseline and 9-15 month HbA1c.
| dose_group | n_patients | mean_baseline_hba1c | mean_daily_dose_mg | mean_hba1c_change |
|---|---|---|---|---|
| Low | 820 | 8.7 | 0.25 | -0.6 |
| Medium | 1260 | 8.9 | 0.5 | -1.0 |
| High | 740 | 9.1 | 1.0 | -1.2 |
Steps
Define time zero as the first qualifying fill after a 365-day washout.
Construct dose from NDC strength, quantity, and days supply; carry stockpiled supply forward but cap implausible daily dose at label-supported maxima.
Model dose continuously with a restricted cubic spline and adjust only for pre-index covariates and pre-index HbA1c, not follow-up tolerability or interim response.
Plot adjusted HbA1c change across dose with 0.50 mg as the reference and mark the observed dose density below the curve.
Run a safety curve for nausea/dehydration separately because benefit and harm may plateau at different doses.
Result
The curve suggests most incremental HbA1c reduction occurs between 0.25 and 0.50 mg, with a smaller gain above 0.50 mg and wider uncertainty at the highest dose. The high-dose tail is not interpreted as causal unless titration and tolerability selection are handled as a treatment strategy.
Runnable example
python implementation
Fit a spline dose-response curve for a continuous outcome with pre-index covariates.
import numpy as np
import pandas as pd
import statsmodels.formula.api as smf
def fit_dose_response(df):
df = df.copy()
knots = np.percentile(df["avg_daily_dose_mg"], [10, 50, 90])
formula = (
"outcome_change ~ cr(avg_daily_dose_mg, knots=[{:.6g}], "
"lower_bound={:.6g}, upper_bound={:.6g}) + baseline_outcome + age + cci"
).format(knots[1], knots[0], knots[2])
fit = smf.ols(formula, data=df).fit(cov_type="HC3")
grid = pd.DataFrame({
"avg_daily_dose_mg": np.linspace(df.avg_daily_dose_mg.quantile(0.02),
df.avg_daily_dose_mg.quantile(0.98), 100),
"baseline_outcome": df.baseline_outcome.mean(),
"age": df.age.mean(),
"cci": df.cci.mean(),
})
grid["predicted_change"] = fit.predict(grid)
return fit, gridr implementation
Fit and plot a natural-spline dose-response curve in R.
library(splines)
fit_dose_response <- function(df) {
qs <- as.numeric(quantile(df$avg_daily_dose_mg, c(0.10, 0.50, 0.90), na.rm = TRUE))
fit <- lm(outcome_change ~ ns(avg_daily_dose_mg, knots = qs[2],
Boundary.knots = qs[c(1, 3)]) +
baseline_outcome + age + cci,
data = df)
grid <- data.frame(
avg_daily_dose_mg = seq(quantile(df$avg_daily_dose_mg, 0.02),
quantile(df$avg_daily_dose_mg, 0.98), length.out = 100),
baseline_outcome = mean(df$baseline_outcome, na.rm = TRUE),
age = mean(df$age, na.rm = TRUE),
cci = mean(df$cci, na.rm = TRUE)
)
grid$predicted_change <- predict(fit, newdata = grid)
list(fit = fit, curve = grid)
}