← Methods repository
concept

Binomial Distribution and the Logit Link

The Bernoulli/binomial distributional family for binary data, the logit transform that maps probabilities onto an unbounded linear scale, and the odds-ratio arithmetic that follows — the probabilistic primitives on which logistic regression, 2x2 table analysis, and case-control inference are all built.

Inferential_Statisticsstatisticsprimitivedistributionsbinary-outcomesodds-ratiologitBernoullibinomial
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

When a clinical outcome is a yes-or-no event — hospitalized or not, responded or not — the underlying math treats each patient's result as a coin flip with a particular probability of landing heads. The logit link is the mathematical bridge that converts those bounded probabilities (which must stay between 0 and 1) into an unbounded number a regression model can use; it does this by working in terms of odds instead of probabilities. The key number the model produces is an odds ratio: how many times more often the event occurred in one group than the other in terms of odds. One honest limitation is that when events are common — say more than 10% of patients — the odds ratio makes differences look bigger than they really are, so analysts should convert it to a risk ratio or risk difference before reporting to clinicians or payers.

What binary outcomes are: from Bernoulli to binomial

Each patient in an RWE cohort contributes a binary endpoint — hospitalized (1) or not (0), responded (1) or not (0), persistent on therapy (1) or not (0). The mathematical model for a single binary trial is the Bernoulli distribution: a random variable Y that equals 1 with probability p and 0 with probability 1 − p. Its probability mass function is P(Y = y) = p^y × (1 − p)^(1 − y), which collapses to P(Y = 1) = p and P(Y = 0) = 1 − p. When n independent patients each share the same event probability p — the simplest case before covariates enter — the total count of events follows a binomial distribution: Bin(n, p), with mean np and variance np(1 − p). The binomial is discrete and right-skewed at small p; it is not a Gaussian bell curve. Logistic regression respects this by modelling each patient's outcome Y_i as Bernoulli(p_i) directly, rather than pretending the outcome is continuous.

Why model probabilities through a link function

The clinical goal is to let each patient's event probability p_i depend on their characteristics X_i: p_i = f(beta_0 + beta'X_i). The simplest approach is the linear probability model (LPM): assume p_i = beta_0 + beta'X_i directly. This fails in a fundamental way — there is nothing to prevent predicted probabilities from exceeding 1 or falling below 0. A regression line fitted to binary data will produce nonsensical predictions outside [0, 1] for covariate combinations near the tails, and generates heteroscedastic residuals throughout the range. The fix is a link function that transforms the bounded [0, 1] probability onto the entire real line (−∞, +∞), so the linear predictor can roam freely without ever violating the probability constraint. Three link functions dominate practice: (1) the logit (log-odds), (2) the probit (inverse-normal CDF), and (3) the log link (used in log-binomial regression for direct risk ratios).

The logit function: log-odds and the logistic curve

The logit transform maps any probability to the real line: logit(p) = log[p / (1 − p)]. The quantity p / (1 − p) is the odds — the ratio of the probability the event occurs to the probability it does not. Odds of 0.25 mean the event is expected once for every four non-events, corresponding to a probability of 0.2. Odds of 1.0 mean equal probability (p = 0.5). Taking the logarithm maps odds from (0, ∞) to log-odds in (−∞, +∞): logit(0.1) ≈ −2.20; logit(0.5) = 0.0; logit(0.9) ≈ 2.20. The inverse is the logistic (expit) function: p = 1 / (1 + exp(−logit)), which maps any real number back to a valid probability and traces the familiar S-shaped logistic curve. A logistic regression model fits logit(p_i) = beta_0 + beta_1 X_{1i} + ... + beta_k X_{ki} by maximum likelihood; the linear predictor is unbounded, but the predicted probability p_i = expit(linear predictor) is always in (0, 1).

Logit vs probit vs log link: why logit dominates

The probit link uses the inverse standard-normal CDF instead of the logit. The probit and logit produce nearly identical fits in the range p ∈ [0.10, 0.90] — they differ mainly in the extreme tails. The probit arises in latent-threshold models where the underlying liability is normally distributed; its coefficients carry no direct odds interpretation. The log link (log-binomial regression) maps the linear predictor to log(p), so exponentiated coefficients are risk ratios (RRs) rather than odds ratios — the more natural quantity for clinical communication when outcome prevalence is high. However, log-binomial models frequently fail to converge because the linear predictor can push predicted probabilities above 1. The standard workaround is Poisson regression with a robust (sandwich) variance — Zou's modified Poisson — which produces adjusted RRs without convergence failures. The logit link dominates for four reasons: (a) it guarantees probabilities in (0, 1) without convergence issues across all outcome prevalence levels; (b) it is the natural likelihood for case-control sampling; (c) it is numerically stable in high-dimensional covariate settings common in claims-based RWE; and (d) standardization via g-computation can convert any logistic model's conditional ORs into the marginal RRs and risk differences (RDs) that decision-makers need.

The odds ratio and its misread as a risk ratio

Exponentiating a logistic coefficient, exp(beta_j), gives the conditional odds ratio (OR): the multiplicative change in the odds of the event for a one-unit increase in X_j, holding all other covariates constant. The single most common interpretation error in published RWE is reading this OR as though it were a risk ratio. These two quantities are equal only when the outcome is rare in both comparison groups — the "rare disease assumption" holds approximately when event risk is below 5–10% in all arms. When the outcome is common — as it frequently is in HEOR for endpoints such as any hospitalization, medication adherence, or treatment switch, which routinely occur in 20–50% of patients — the OR is numerically further from 1.0 than the RR, and overstates the apparent magnitude of the effect in both directions (harm and benefit). In the worked example below: the outcome is common (20% in Group A, 10% in Group B), yielding RR = 2.0 exactly and OR = 2.25. Reporting OR = 2.25 and stating "the treatment was associated with a 2.25-fold higher risk" is incorrect and misleads clinicians and HTA reviewers about the true magnitude of the association.

Noncollapsibility: distinct from confounding

Noncollapsibility is a mathematical property of the odds ratio itself, not a form of bias or confounding error. Even with perfectly balanced randomization and no confounding whatsoever, a conditional OR (from a logistic model adjusting for covariates) will differ numerically from the marginal OR (from an unadjusted 2×2 table or from inverse-probability weighting). Adding a strong risk-factor covariate to a logistic model moves the conditional OR away from the null even when that covariate is perfectly balanced between treatment arms and is not a confounder. This occurs because the logistic link is nonlinear: averaging over a covariate distribution does not recover the same OR as conditioning on it. By contrast, the risk difference and risk ratio are collapsible: adding a balanced predictor does not systematically shift the marginal RD or RR. The practical implication is that observed differences in ORs across studies with different covariate adjustment sets may reflect noncollapsibility rather than true confounding; this distinction must be pre-specified in the estimand. Standardization to marginal effects (see marginal-effects-and-interpretation-of-inferential-statistics-rwe) converts conditional logistic estimates into the collapsible marginal quantities that support cross-study comparisons and HTA decisions.

Case-control studies: why the OR is the only estimable quantity

In a case-control design, investigators sample on the outcome — a predetermined number of cases and controls are enrolled, deliberately breaking the link between case frequency in the sample and prevalence in the source population. Because sampling fractions differ by outcome status, the absolute event rates in the enrolled sample do not reflect the true population incidence. Absolute risks (events / total enrolled) are therefore meaningless. What is preserved under outcome-stratified sampling is the cross-product ratio: (cases_exposed / cases_unexposed) / (controls_exposed / controls_unexposed) = OR. This algebraic invariance is why the OR is the natural and only directly estimable effect measure in case-control studies, and why logistic regression is the canonical analysis for such data. Converting a case-control OR to an approximate RR requires external data on the absolute event rate in the source population from which cases and controls were drawn.

Interpreting the output

Consider a logistic model comparing a new treatment (Group A) versus standard care (Group B) for a binary event, yielding an adjusted logistic coefficient of 0.811 with 95% CI 0.22 to 1.40.

Formal interpretation: exp(0.811) = 2.25 — patients in Group A had 2.25 times the adjusted odds of the event compared to Group B, holding covariates fixed. This is a conditional (covariate-specific, model-based) odds ratio. In the worked example (Group A: 20/100 = 0.20 risk; Group B: 10/100 = 0.10 risk), the unadjusted OR is exactly 2.25 while the RR is exactly 2.0. Because the outcome is common (20% in the treated arm), the OR overstates the relative frequency; the conditional OR also shifts when strong but non-confounding predictors are added to the model — noncollapsibility, not confounding. A 95% CI for the log-OR of [0.22, 1.40] translates to a 95% CI for the OR of approximately [1.25, 4.07].

Practical interpretation for clinicians and HTA bodies: for rare outcomes (risk below about 10% in both arms), the OR and RR are sufficiently similar that it is defensible to state "the adjusted OR was 2.25, approximately corresponding to a 2.25-fold higher risk." For common outcomes — as in this example — state instead: "the adjusted OR was 2.25; because the event was common (20% in the treated arm), the corresponding risk ratio is approximately 2.0 and the absolute risk difference is approximately 10 percentage points. The absolute risk difference is reported alongside the OR for clinical interpretation."

Pros, cons, and trade-offs

Logit link (logistic regression): - Pros: guarantees probabilities in (0, 1); numerically stable at all prevalence levels; natural Bernoulli likelihood for binary data; the only directly interpretable effect measure from case-control sampling; stable in high-dimensional covariate settings; easily standardized to marginal RD and RR by g-computation; the standard outcome model inside g-computation, AIPW, and TMLE for binary outcomes. - Cons: native measure is the OR, which is noncollapsible, further from 1.0 than the RR for common outcomes, and routinely misread as a risk ratio; conditional ORs from logistic models with different covariate sets cannot be directly compared. - When to prefer: case-control design; any binary endpoint when the analyst will standardize to marginal effects; outcomes too common for log-binomial to converge; rare outcomes where OR ≈ RR.

Log link (log-binomial or Poisson-robust): - Pros: exponentiated coefficient is the RR directly, the quantity clinicians and HTA prefer. - Cons: log-binomial frequently fails to converge; Poisson-robust requires a sandwich variance correction; inappropriate for case-control data where the OR is the estimable quantity. - When to prefer: common outcome, RR is the pre-specified estimand, complete follow-up in a fixed-window cohort.

Linear probability model (OLS on 0/1): - Pros: coefficients are risk differences; collapsible; familiar to non-statisticians. - Cons: predictions violate [0, 1] at boundary covariate values; heteroscedastic residuals; naive standard errors require correction. - When to prefer: only as a quick sanity check for risk differences, not for primary inference.

When to use

Use the binomial/logit framework when: (1) the endpoint is binary (yes/no) over a fixed risk window with complete follow-up; (2) the study design is case-control, where the OR is the only estimable measure and logistic regression is the canonical analysis; (3) the analyst will standardize from the fitted logistic model to marginal RDs and RRs — the most defensible workflow for common outcomes; (4) the outcome is rare or separation concerns make the log link infeasible; (5) the binary outcome is the outcome model inside g-computation, AIPW, or TMLE.

When NOT to use

  • When RR or RD is the communication target and the outcome is common (risk at or above 10% in
  • Correlated binary outcomes — multiple eligible episodes per patient, or clustering within
  • Perfect or quasi-complete separation in small samples: maximum likelihood estimates diverge
  • Variable follow-up or informative censoring: a fixed-window logistic model treats all

Worked example

Scenario

A health outcomes team is evaluating a new therapy (Group A) versus standard care (Group B) for a binary endpoint: hospitalized within 90 days (1 = yes, 0 = no). Group A has 100 patients, Group B has 100 patients. Twenty patients in Group A were hospitalized; ten patients in Group B were hospitalized. The team computes the risk ratio and the odds ratio from the 2x2 table and observes that the two numbers are not the same — even though they describe identical data — because the outcome is common in both arms.

Dataset

90-day hospitalization: counts per arm (n=100 per arm)

grouphospitalized_yeshospitalized_nototal
A (new therapy)2080100
B (standard care)1090100

Steps

  • Read Group A cells: events = 20, non-events = 80, total = 100. Risk A = 20/100 = 0.2. Odds A = 20/80 = 0.25. Interpretation: 1 event for every 4 non-events in Group A.

  • Read Group B cells: events = 10, non-events = 90, total = 100. Risk B = 10/100 = 0.1. Odds B = 10/90 = 0.111. Interpretation: roughly 1 event for every 9 non-events in Group B.

  • Compute the risk ratio: RR = 0.2 / 0.1 = 2.0. Group A patients have twice the risk of hospitalization compared to Group B. This is a ratio of probabilities.

  • Compute the odds ratio using the cross-product formula: OR = (20 90) / (80 10) = 1800 / 800 = 2.25. The OR (2.25) is larger than the RR (2.0) because the outcome is common. The logistic regression coefficient for group membership equals log(OR) = log(2.25) approximately 0.811, and exp(0.811) approximately 2.25 recovers the OR.

  • The divergence between OR and RR grows with outcome prevalence. Here, OR = 2.25 exceeds RR = 2.0 by about 12.5 percent relatively. For a rare outcome where risk in both arms is below 5%, OR and RR would be nearly indistinguishable. Reporting OR = 2.25 as though it were a risk ratio overstates the association for a common outcome like hospitalization.

Result

Group A: risk = 20/100 = 0.2, odds = 20/80 = 0.25. Group B: risk = 10/100 = 0.1, odds = 10/90 = 0.111. RR = 0.2 / 0.1 = 2.0. OR = (20 90) / (80 10) = 1800 / 800 = 2.25. The OR (2.25) exceeds the RR (2.0) because the outcome is common. The logistic coefficient is log(2.25) approximately 0.811. The log-Wald 95% CI for the OR uses SE = sqrt(1/20 + 1/80 + 1/10 + 1/90) approximately 0.417, giving the interval exp(0.811 ± 1.96 × 0.417) approximately [0.99, 5.09] for a sample of this size; this interval includes 1.0, reflecting the modest sample size. Analysts reporting this result to clinicians should state the absolute risk difference (20% minus 10% = 10 percentage points) alongside the OR.

Runnable example

python implementation

Bernoulli/binomial distribution mechanics (scipy.stats.binom), the logit/expit pair (scipy.special.logit and expit), the 2x2 OR vs RR arithmetic from the worked example, and statsmodels logistic regression confirming that the coefficient equals log(OR)....

import numpy as np
from scipy.stats import binom
from scipy.special import logit, expit
import statsmodels.formula.api as smf
import pandas as pd

# ── 1. Bernoulli / Binomial distribution ────────────────────────────────────
# n=100 patients in each arm; Group A has event probability p=0.2
p_a, p_b = 0.2, 0.1
dist_a = binom(n=100, p=p_a)

print("--- Binomial distribution (Group A, n=100, p=0.2) ---")
print(f"Expected events : {dist_a.mean():.1f}")
print(f"Variance        : {dist_a.var():.1f}")
print(f"P(exactly 20)   : {dist_a.pmf(20):.4f}")
print(f"P(15 to 25)     : {dist_a.cdf(25) - dist_a.cdf(14):.4f}")

# ── 2. Logit / expit round-trip ─────────────────────────────────────────────
print("\n--- Logit / expit (qlogis / plogis in R) ---")
print(f"{'p':>5}  {'odds':>8}  {'logit':>8}  {'expit(logit)':>14}")
for p_val in [0.1, 0.2, 0.5, 0.9]:
    lo   = logit(p_val)                 # log-odds = log(p/(1-p))
    odds = p_val / (1 - p_val)
    back = expit(lo)                    # inverse logit: recover p
    print(f"{p_val:5.1f}  {odds:8.4f}  {lo:8.4f}  {back:14.4f}")

# ── 3. 2x2 table: OR vs RR (the worked example arithmetic) ──────────────────
a, b_c, c, d = 20, 80, 10, 90          # a=events_A, b=non_A, c=events_B, d=non_B
risk_a = a / (a + b_c)                 # 20/100 = 0.2
risk_b = c / (c + d)                   # 10/100 = 0.1
odds_a = a / b_c                        # 20/80  = 0.25
odds_b = c / d                          # 10/90  = 0.111
rr     = risk_a / risk_b               # 0.2/0.1 = 2.0
or_val = (a * d) / (b_c * c)           # (20*90)/(80*10) = 1800/800 = 2.25

print("\n--- 2x2 table: OR vs RR ---")
print(f"risk A = {risk_a:.3f}, odds A = {odds_a:.4f}")
print(f"risk B = {risk_b:.3f}, odds B = {odds_b:.4f}")
print(f"RR     = {rr:.4f}   (ratio of probabilities)")
print(f"OR     = {or_val:.4f}  (ratio of odds; larger than RR because outcome is common)")
print(f"log(OR)= {np.log(or_val):.4f}  (the logistic regression coefficient)")

# ── 4. Logistic regression: coefficient must equal log(OR) ──────────────────
df = pd.DataFrame(
    [{"group": 1, "event": 1}] * 20 +   # A events
    [{"group": 1, "event": 0}] * 80 +   # A non-events
    [{"group": 0, "event": 1}] * 10 +   # B events
    [{"group": 0, "event": 0}] * 90      # B non-events
)
fit = smf.logit("event ~ group", data=df).fit(disp=0)
coef  = fit.params["group"]
ci    = fit.conf_int().loc["group"]

print("\n--- Logistic regression ---")
print(f"Coefficient for group : {coef:.4f}  (= log(OR) = {np.log(or_val):.4f})")
print(f"exp(coef)             : {np.exp(coef):.4f}  (= OR = {or_val:.4f})")
print(f"95% CI (log-OR)       : [{ci[0]:.3f}, {ci[1]:.3f}]")
print(f"95% CI (OR)           : [{np.exp(ci[0]):.3f}, {np.exp(ci[1]):.3f}]")
print("Note: OR > RR (2.25 > 2.0) because outcome is common (20% in Group A).")
print("For clinical communication, compute marginal RD = risk_A - risk_B or use g-comp.")
r implementation

Binomial PMF/CDF (dbinom/pbinom), the logit/expit pair (qlogis/plogis — base R), the 2x2 cross-product OR vs RR arithmetic, and glm() with binomial family confirming the logistic coefficient equals log(OR). All base-R except confint() which requires the...

# ── 1. Binomial distribution ────────────────────────────────────────────────
p_a <- 0.2; p_b <- 0.1; n <- 100
cat("--- Binomial distribution (Group A, n=100, p=0.2) ---\n")
cat(sprintf("Expected events : %.1f\n", n * p_a))
cat(sprintf("Variance        : %.1f\n", n * p_a * (1 - p_a)))
cat(sprintf("P(exactly 20)   : %.4f\n", dbinom(20, size=n, prob=p_a)))
cat(sprintf("P(15 to 25)     : %.4f\n", pbinom(25, n, p_a) - pbinom(14, n, p_a)))

# ── 2. qlogis (logit) and plogis (expit / inverse-logit) ────────────────────
cat("\n--- Logit / expit ---\n")
cat(sprintf("%-6s %-9s %-9s %-12s\n", "p", "odds", "logit", "plogis(logit)"))
for (pv in c(0.1, 0.2, 0.5, 0.9)) {
  lo <- qlogis(pv)                       # logit: log(p / (1 - p))
  cat(sprintf("%-6.1f %-9.4f %-9.4f %-12.4f\n",
              pv, pv/(1-pv), lo, plogis(lo)))
}

# ── 3. 2x2 table: OR vs RR ──────────────────────────────────────────────────
a <- 20; b_c <- 80; cc <- 10; d <- 90
risk_a <- a/(a+b_c); risk_b <- cc/(cc+d)     # 0.2, 0.1
odds_a <- a/b_c;     odds_b <- cc/d           # 0.25, 0.111
rr_val <- risk_a / risk_b                     # 0.2/0.1 = 2.0
or_val <- (a * d) / (b_c * cc)                # (20*90)/(80*10) = 2.25
cat(sprintf("\nRR = %.4f, OR = %.4f  (OR > RR: outcome common at %.0f%%)\n",
            rr_val, or_val, risk_a*100))

# Cross-check: fisher.test returns OR from exact hypergeometric distribution
tbl <- matrix(c(a, b_c, cc, d), nrow=2, byrow=TRUE,
              dimnames=list(c("A","B"), c("Event","No-event")))
ft <- fisher.test(tbl)
cat(sprintf("fisher.test OR  = %.4f  (should match cross-product %.4f)\n",
            ft$estimate, or_val))

# ── 4. glm with binomial family and logit link ───────────────────────────────
df <- data.frame(
  group = c(rep(1,100), rep(0,100)),
  event = c(rep(1,20), rep(0,80), rep(1,10), rep(0,90))
)
fit    <- glm(event ~ group, family=binomial(link="logit"), data=df)
coef_g <- coef(fit)["group"]
# confint() uses profile-likelihood; suppressMessages to suppress one iteration note
ci_g   <- suppressMessages(confint(fit))["group", ]

cat(sprintf("\nglm coefficient : %.4f  (= log(OR) = %.4f)\n",
            coef_g, log(or_val)))
cat(sprintf("exp(coef)       : %.4f  (= OR = %.4f)\n", exp(coef_g), or_val))
cat(sprintf("95%% CI (OR)     : [%.3f, %.3f]\n", exp(ci_g[1]), exp(ci_g[2])))
cat("Note: for marginal RR/RD from this logistic fit use marginaleffects::avg_comparisons()\n")