← Methods repository
concept

Risk Ratio and Risk Difference

The risk ratio (RR, relative risk) is the ratio of two incidence proportions — events per persons at risk over a defined time window — and the risk difference (RD) is their absolute gap; together they form the primary effect-measure pair for cohort and trial data, quantifying how much more (or less) common an outcome is in one group than another in both relative and absolute terms.

Inferential_Statisticsstatisticsprimitiveeffect-measuresriskepidemiologyincidence-proportionrelative-riskabsolute-risk
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 risk is the fraction of patients in a group who had a given health event during a fixed time window — for example, 12 out of 100 patients hospitalized within one year gives a risk of 0.12. The risk ratio compares two groups by dividing their risks (a ratio of 2.0 means one group has twice the risk), while the risk difference subtracts one from the other to show how many extra events occurred per 100 people. Both numbers are needed together because doubling a tiny risk still produces a small absolute burden, and you cannot make a clinical or policy decision from either measure alone.

What is risk? The three denominators

Risk, rate, and odds are three distinct ways to express how common an event is in a population, and confusing them is one of the most persistent errors in epidemiological reporting. Each has a different denominator and a different meaning.

Risk

(cumulative incidence proportion) is the fraction of individuals in a group who experience the event during a specified time window: risk = events / persons_at_risk_at_start. A 12-month risk of 0.12 means 12 out of every 100 patients who were event-free at the start experienced the event during the next year. Risk is dimensionless and bounded [0, 1]. Its denominator is persons — not person-time — so it requires every participant to have the same (or appropriately handled) observable follow-up window. In claims and EHR analyses with variable follow-up, patients whose observable time is shorter than the chosen window must be handled via censoring (see `censoring-mechanisms-rwe`) or the analysis must be restricted to those with complete observable follow-up. Without a fixed, common time horizon, you are computing a rate, not a risk.

Rate

(incidence rate) expresses events per unit of person-time: rate = events / total_person_time. A rate of 0.12 per person-year is not the same as a risk of 0.12 — the rate accommodates variable follow-up, is unbounded, and belongs to the Poisson rather than the binomial family (see `incidence-rate-calculation-rwe`). For time-to-event data with variable follow-up and censoring, the hazard ratio family is the natural effect measure, not the RR.

Odds

express the ratio of the event probability to the non-event probability: odds = p / (1 − p). Odds of 0.136 correspond to a risk of 0.12. The odds ratio (OR) from logistic regression overstates relative associations for common outcomes (risk above approximately 10%) and is the only directly estimable measure in case-control studies where absolute risks are uninformative. The OR is NOT interchangeable with the RR when the outcome is common — see `binomial-distribution-logit-link` for the full treatment of the logit link and the OR≠RR trap.

Risk ratio and risk difference: definitions and arithmetic

Given a fixed time window T, a group of n_e exposed individuals with a_e events, and a group of n_u unexposed individuals with a_u events:

risk_exposed = a_e / n_e risk_unexposed = a_u / n_u RR = risk_exposed / risk_unexposed RD = risk_exposed − risk_unexposed

The risk ratio (RR), also called the relative risk or cumulative incidence ratio, is a dimensionless multiplier. An RR of 2.0 means the exposed group has twice the cumulative incidence of the unexposed group over the stated window. It is asymmetric with respect to the event scale: if the RR of experiencing disease is 2.0, the RR of surviving (1 − risk_exposed) / (1 − risk_unexposed) is NOT 0.5 except when risks are very small. This means "twice the risk of disease" and "half the protection" are not equivalent statements, and the RR direction should always be stated explicitly.

The risk difference (RD), also called the absolute risk increase (when RD > 0) or absolute risk reduction (when RD < 0, for a beneficial exposure), is the arithmetic gap between the two risks. An RD of 0.06 means 6 additional events per 100 exposed individuals over the stated window — or 60 additional events per 1,000. The RD carries the same unit as the risk (a proportion), making it the most policy-interpretable measure for public health, payers, and HTA bodies: it directly answers "how many events in this population are attributable to this exposure over this horizon?"

Why both measures are necessary: the relative-looks-big / absolute-is-small problem

The relative and absolute measures carry complementary information that neither alone conveys. An RR of 2.0 sounds dramatic — "doubled risk." But "twice the risk" of a rare event can be clinically negligible: if the baseline risk is 0.001 (1 in 1,000), an RR of 2.0 yields an RD of only 0.001 — 1 additional case per 1,000 exposed. Conversely, a "modest" RR of 1.3 on a 40% baseline risk generates an RD of 12 percentage points — 12 additional events per 100 exposed individuals. Media reporting of relative risks without the absolute baseline is the dominant source of health numeracy errors in public communication, and regulatory and HTA bodies have accordingly required both measures in evidence packages for decades: FDA guidance on benefit-risk labeling and EMA statistical principles consistently require the RD (or its NNT/NNH derivative) alongside any relative measure. Presenting only the RR systematically misleads about public-health burden; presenting only the RD without the RR prevents cross-population comparison.

RR baseline-risk dependence, asymmetry, and collapsibility

The RD is a direct product of the RR and the baseline risk: RD = risk_unexposed × (RR − 1). This means the same RR implies very different absolute burdens in populations with different baseline risks: an RR of 2.0 applied to a 30% baseline yields RD = 0.30, while the same RR applied to a 3% baseline yields RD = 0.03 — a ten-fold difference in absolute burden. Because the RR is less sensitive to the level of baseline risk, it is the preferred measure for transporting effects across populations and for meta-analysis — though it is not completely population-independent when effect modification varies across subgroups.

Both the RR and the RD are collapsible: adding a balanced, non-confounding predictor to a model does not systematically shift the marginal RR or RD. This is an advantage over the odds ratio, which is non-collapsible and shifts when a strong predictor is added even when that predictor is perfectly balanced across treatment arms and is not a confounder (see `binomial-distribution-logit-link`). Collapsibility means that differences between adjusted and unadjusted RRs or RDs reveal true confounding rather than a mathematical artefact of the link function.

Estimation with covariate adjustment

For unadjusted estimation, compute RR and RD directly from a 2×2 table. Confidence intervals for the RR use the Woolf (log-normal) method: SE(log RR) = sqrt(1/a − 1/n_e + 1/c − 1/n_u); exponentiate the log-scale limits. Confidence intervals for the RD use the Wald method: SE(RD) = sqrt(r_e(1−r_e)/n_e + r_u(1−r_u)/n_u). For adjusted estimation with covariates, three approaches dominate:

Log-binomial regression: GLM with binomial family and log link; exponentiated coefficients are adjusted RRs. Critical practical limitation: the log link can push predicted probabilities above 1.0 for extreme covariate values, causing frequent convergence failures in high-dimensional real-world datasets.

Poisson regression with robust (sandwich) variance (Zou 2004): a Poisson GLM with log link and a sandwich covariance matrix yields adjusted RRs without the convergence failures of log-binomial. The misspecification (Poisson model for binary data) is harmless for point estimates, and the robust variance corrects standard errors. This modified Poisson approach is now the dominant standard for adjusted RR estimation in pharmacoepidemiology and comparative effectiveness research.

Standardization / g-computation for marginal RD and RR: fit any outcome model (e.g., logistic regression for individual event probability), predict each patient's counterfactual outcome probability under both exposed and unexposed scenarios, and average the difference or ratio across the population. G-computation yields marginal (population-averaged) adjusted RD and RR with correct uncertainty via bootstrapping. It is the most robust alternative to identity-link binomial regression (which faces convergence failures below 0) and produces estimates directly interpretable for HTA.

Interpreting the output

Consider a 12-month cohort study: 300 patients exposed to a new drug, 300 unexposed to a comparator. Events: exposed = 36, unexposed = 18. Estimated RR = 2.0, 95% CI 1.2–3.4; RD = 0.06, 95% CI 0.02–0.10.

Formal interpretation — RR: the 12-month incidence proportion among the exposed is 0.12 (36 / 300) and among the unexposed is 0.06 (18 / 300). The risk ratio of 2.0 means the 12-month risk among the exposed is 2.0 times that among the unexposed. This is a measure of association; whether it reflects a causal effect depends on whether confounding has been adequately controlled. Risk requires a stated time window to be meaningful — this RR is for 12 months only and cannot be extended without re-estimation. The 95% CI of (1.2, 3.4) means: in repeated samples from the same population under the same design, 95% of the constructed intervals would contain the true RR. RD = 0.06 (95% CI 0.02–0.10): 6 additional events per 100 exposed patients over 12 months, or 60 per 1,000.

Practical interpretation for clinicians and HTA bodies: "Twice the risk" sounds alarming, but the absolute context matters. Here, doubling means going from 6 events to 12 events per 100 patients over a year — about 1 extra event for every 17 patients exposed (NNH = 1 / 0.06 ≈ 17). Whether 17 is large or small depends on event severity, cost and tolerability of the exposure, and available alternatives. A headline that says "drug doubles risk of event" communicates the RR = 2.0 correctly but conceals that the baseline risk is only 6%, making the absolute increase modest. Presenting RR = 2.0 alongside RD = 0.06 (60 per 1,000 over 12 months; NNH ≈ 17) gives decision-makers the complete picture needed for clinical and economic judgment.

Pros, cons, and trade-offs

Risk ratio: - Pros: scale-free and approximately portable across populations with different baseline risks; the natural effect measure for prospective cohort and trial data with a fixed risk window; multiplicative (null = 1.0); collapsible under balanced predictors; preferred for meta-analysis and transportability to other populations. - Cons: gives no indication of absolute burden; "twice the risk" of a rare event may be clinically negligible; asymmetric — the RR of the event and the RR of the non-event are not complementary; does not directly answer "how many additional patients were affected?" - When to prefer: communicating the strength of an association; transporting effects across populations; pre-specified primary effect measure in a cohort study.

Risk difference: - Pros: directly answers the public-health and HTA question (how many additional events per N exposed?); collapsible; the basis for NNT/NNH (NNT = 1/RD, see `number-needed-to-treat-rwe`); directly interpretable for budget-impact and preventive-medicine communication; preferred by regulatory bodies for labeling alongside any relative measure. - Cons: highly baseline-risk-dependent — a trial RD cannot be transported to a different-risk population without re-anchoring; can look trivially small when the relative effect is large on a rare outcome. - When to prefer: HTA, payer, and clinical communication; whenever the policy question is "how many additional events are caused by this exposure in this population?"

Versus OR: the OR from logistic regression overstates relative effects for common outcomes (risk ≥ 10%), is non-collapsible, and is the only directly estimable measure in case-control studies. Use RR and RD for cohort data; use OR for case-control designs or when the odds scale is explicitly required, then convert to marginal RD/RR via g-computation (see `binomial-distribution-logit-link`).

When to use

Use RR and RD when: (1) the endpoint is binary over a defined, fixed risk window with complete follow-up or appropriate censoring handled; (2) the study design is a prospective cohort, active-comparator new-user design, randomized trial, or any design where person-count denominators can be correctly constructed; (3) both a relative measure (for portability and meta-analysis) and an absolute measure (for HTA and clinical communication) are required by the protocol; (4) downstream NNT/NNH communication is planned; (5) g-computation or Poisson-robust regression will be used for covariate-adjusted estimates.

When NOT to use

  • Without a defined risk window or with heavy differential censoring: risk is undefined without a
  • In case-control studies: sampling on outcome status makes absolute risks in the enrolled sample
  • Transporting an RD without re-anchoring to the local baseline risk: an RD from a trial or RWE
  • Comparing RRs across populations with very different baseline risks as if they are equivalent: an

Worked example

Scenario

A health outcomes team studies a new drug's association with a hospital event over 12 months in a claims database. They identify 300 new users of the drug (exposed) and 300 matched new users of a comparator drug (unexposed), each followed for 12 months from their index date (first fill). They count events, compute the 2x2 risk table, derive the RR and RD, then express the RD on a per-1,000 scale and compute the NNH.

Dataset

12-month event counts for exposed and unexposed new-user cohorts (n=300 per group).

groupeventsn
exposed36300
unexposed18300

Steps

  • Compute the exposed-group risk: 36 events out of 300 patients, so risk = 36/300 = 0.12. Twelve out of every 100 exposed patients had the event during the 12-month window.

  • Compute the unexposed-group risk: 18 events out of 300 patients, so risk = 18/300 = 0.06. Six out of every 100 unexposed patients had the event over the same window.

  • Compute the risk ratio: RR = 0.12/0.06 = 2.0. The exposed group has twice the 12-month risk of the unexposed group. This is the relative effect.

  • Compute the risk difference: RD = 0.12 - 0.06 = 0.06. There are 6 additional events per 100 exposed patients compared with the unexposed over the 12-month window.

  • Express the RD on a per-1,000 scale: 0.06 * 1000 = 60 additional events per 1,000 exposed patients. This is the public-health framing preferred by payers and HTA bodies.

  • Compute NNH: 1/0.06 = 16.7, rounded up to 17. About 17 patients must be exposed (instead of receiving the comparator) for one additional event to occur over 12 months.

Result

Exposed risk = 36/300 = 0.12; Unexposed risk = 18/300 = 0.06. RR = 0.12/0.06 = 2.0: exposed patients have twice the 12-month event risk. RD = 0.12 - 0.06 = 0.06, equal to 0.06 * 1000 = 60 extra events per 1,000 exposed over 12 months. NNH = 1/0.06 = 16.7, round up to 17. Both measures are needed: the RR communicates relative doubling while the RD shows that only 6 additional patients per 100 are affected — about 1 in every 17 exposed patients over the 12-month window.

Runnable example

python implementation

Manual 2x2 computation of RR and RD from the worked example (36/300 vs 18/300), validated against statsmodels Table2x2 CIs. Includes the Woolf (log-normal) 95% CI for the RR and the Wald 95% CI for the RD. Also demonstrates Poisson regression with robust...

import numpy as np
from scipy import stats
import statsmodels.api as sm
from statsmodels.stats.contingency_tables import Table2x2
import pandas as pd

# ── 1. Manual 2x2 computation (worked example) ──────────────────────────────
# Exposed:   36 events / 300 patients -> risk = 0.12
# Unexposed: 18 events / 300 patients -> risk = 0.06
a, b = 36, 264    # exposed:   events, non-events
c, d = 18, 282    # unexposed: events, non-events
n_e, n_u = a + b, c + d    # 300, 300

r_e = a / n_e     # exposed risk   = 36/300 = 0.12
r_u = c / n_u     # unexposed risk  = 18/300 = 0.06
rr  = r_e / r_u   # risk ratio      = 0.12/0.06 = 2.0
rd  = r_e - r_u   # risk difference = 0.12 - 0.06 = 0.06

print(f"Exposed risk   = {a}/{n_e} = {r_e:.4f}")
print(f"Unexposed risk = {c}/{n_u} = {r_u:.4f}")
print(f"RR = {r_e:.4f} / {r_u:.4f} = {rr:.4f}")
print(f"RD = {r_e:.4f} - {r_u:.4f} = {rd:.4f}  ({rd * 1000:.0f} per 1,000)")
print(f"NNH = 1 / {rd:.4f} = {1/rd:.1f}  (round up to {int(np.ceil(1/rd))})")

# ── 2. Woolf (log-normal) 95% CI for the RR ─────────────────────────────────
# SE(log RR) = sqrt(1/a - 1/n_e + 1/c - 1/n_u)
se_log_rr = np.sqrt(1/a - 1/n_e + 1/c - 1/n_u)
z = stats.norm.ppf(0.975)
rr_ci = (np.exp(np.log(rr) - z * se_log_rr),
         np.exp(np.log(rr) + z * se_log_rr))
print(f"\nRR 95% CI (Woolf): ({rr_ci[0]:.3f}, {rr_ci[1]:.3f})")

# ── 3. Wald 95% CI for the RD ────────────────────────────────────────────────
se_rd = np.sqrt(r_e * (1 - r_e) / n_e + r_u * (1 - r_u) / n_u)
rd_ci = (rd - z * se_rd, rd + z * se_rd)
print(f"RD 95% CI (Wald):  ({rd_ci[0]:.4f}, {rd_ci[1]:.4f})")

# ── 4. statsmodels Table2x2: cross-validated CIs ─────────────────────────────
# Layout: [[exposed_events, exposed_non], [unexposed_events, unexposed_non]]
tbl = Table2x2(np.array([[a, b], [c, d]]))
rr_sm = tbl.riskratio
rd_sm = tbl.riskdiff
print(f"\nstatsmodels RR = {rr_sm.statistic:.4f}  "
      f"95% CI ({rr_sm.conf_int()[0]:.3f}, {rr_sm.conf_int()[1]:.3f})")
print(f"statsmodels RD = {rd_sm.statistic:.4f}  "
      f"95% CI ({rd_sm.conf_int()[0]:.4f}, {rd_sm.conf_int()[1]:.4f})")

# ── 5. Poisson GLM with robust variance: adjusted RR (Zou 2004) ──────────────
# Reconstruct individual-level data from summary counts
df = pd.DataFrame({
    "exposed": [1] * n_e + [0] * n_u,
    "event":   [1] * a + [0] * b + [1] * c + [0] * d,
})
X = sm.add_constant(df["exposed"])
# cov_type="HC0" = heteroscedasticity-consistent (sandwich) variance (Zou 2004)
fit = sm.GLM(df["event"], X,
             family=sm.families.Poisson()).fit(cov_type="HC0")
adj_rr    = np.exp(fit.params["exposed"])
adj_rr_ci = np.exp(fit.conf_int().loc["exposed"])
print(f"\nPoisson+robust (Zou 2004) RR = {adj_rr:.4f}  "
      f"95% CI ({adj_rr_ci[0]:.3f}, {adj_rr_ci[1]:.3f})")
print("For ADJUSTED RR: add confounders to the model formula.")
print("For ADJUSTED RD: use g-computation — predict P(event|exp=1/0) per patient,")
print("  average the difference; bootstrap the full procedure for CIs.")
r implementation

Manual 2x2 RR and RD computation from the worked example with Woolf (log) and Wald CIs in base R, validated against epitools::riskratio. Demonstrates Poisson GLM with sandwich (robust) variance via the sandwich package for adjusted RR (Zou 2004). Also shows...

# ── 1. Manual 2x2 computation (worked example) ──────────────────────────────
a  <- 36;  b_n <- 264   # exposed:   events, non-events
cc <- 18;  d   <- 282   # unexposed: events, non-events
n_e <- a + b_n; n_u <- cc + d   # 300, 300

r_e <- a  / n_e    # exposed risk   = 36/300 = 0.12
r_u <- cc / n_u    # unexposed risk  = 18/300 = 0.06
rr  <- r_e / r_u   # risk ratio      = 0.12/0.06 = 2.0
rd  <- r_e - r_u   # risk difference = 0.12 - 0.06 = 0.06

cat(sprintf("Exposed risk   = %d/%d = %.4f\n", a, n_e, r_e))
cat(sprintf("Unexposed risk = %d/%d = %.4f\n", cc, n_u, r_u))
cat(sprintf("RR = %.4f,  RD = %.4f  (%.0f per 1,000)\n", rr, rd, rd * 1000))
cat(sprintf("NNH = 1/%.4f = %.1f (round up to %d)\n", rd, 1/rd, ceiling(1/rd)))

# ── 2. Woolf CI for RR and Wald CI for RD (base R) ─────────────────────────
se_log_rr <- sqrt(1/a - 1/n_e + 1/cc - 1/n_u)
z <- qnorm(0.975)
rr_ci <- exp(log(rr) + c(-1, 1) * z * se_log_rr)
cat(sprintf("RR 95%% CI (Woolf): (%.3f, %.3f)\n", rr_ci[1], rr_ci[2]))

se_rd <- sqrt(r_e * (1 - r_e) / n_e + r_u * (1 - r_u) / n_u)
rd_ci <- rd + c(-1, 1) * z * se_rd
cat(sprintf("RD 95%% CI (Wald):  (%.4f, %.4f)\n", rd_ci[1], rd_ci[2]))

# ── 3. epitools::riskratio (cross-validation) ───────────────────────────────
if (requireNamespace("epitools", quietly = TRUE)) {
  tbl <- matrix(c(a, b_n, cc, d), nrow = 2, byrow = TRUE,
                dimnames = list(c("exposed", "unexposed"), c("event", "noevent")))
  res_rr <- epitools::riskratio(tbl, method = "log")
  cat(sprintf("\nepitools RR = %.4f  95%% CI (%.3f, %.3f)\n",
              res_rr$measure[2, 1], res_rr$measure[2, 2], res_rr$measure[2, 3]))
}

# ── 4. Poisson GLM with sandwich variance: adjusted RR (Zou 2004) ───────────
df <- data.frame(
  exposed = c(rep(1L, n_e), rep(0L, n_u)),
  event   = c(rep(1L, a),  rep(0L, b_n), rep(1L, cc), rep(0L, d))
)
fit_pois <- glm(event ~ exposed, family = poisson(link = "log"), data = df)
if (requireNamespace("sandwich", quietly = TRUE)) {
  library(sandwich)
  se_rob   <- sqrt(diag(sandwich(fit_pois)))["exposed"]
  coef_exp <- coef(fit_pois)["exposed"]
  rr_adj   <- exp(coef_exp)
  rr_ci_adj <- exp(coef_exp + c(-1, 1) * z * se_rob)
  cat(sprintf("\nPoisson+robust RR = %.4f  95%% CI (%.3f, %.3f)  [Zou 2004]\n",
              rr_adj, rr_ci_adj[1], rr_ci_adj[2]))
  cat("For ADJUSTED RR: add confounders to the model formula.\n")
}

# ── 5. Identity-link binomial GLM: marginal RD (may not converge) ───────────
fit_id <- tryCatch(
  glm(event ~ exposed, family = binomial(link = "identity"), data = df),
  warning = function(w) NULL, error = function(e) NULL
)
if (!is.null(fit_id)) {
  rd_adj    <- coef(fit_id)["exposed"]
  rd_ci_adj <- suppressMessages(confint(fit_id))["exposed", ]
  cat(sprintf("Identity-link RD = %.4f  95%% CI (%.4f, %.4f)\n",
              rd_adj, rd_ci_adj[1], rd_ci_adj[2]))
} else {
  cat("Identity-link binomial did not converge; use g-computation for marginal RD.\n")
}