AdvancedIndependently reviewed, not yet spot-checked by a human

Conditional logistic regression

Why matched data cannot be fitted with ordinary logistic regression, what strata() actually conditions away, what happens when you put the matching variables back into the model (nothing happens, and nothing tells you), and how the 1:1 case relates to McNemar's test — which is four different numbers, not one.

What this model is for

Matching is a design-stage device for dealing with confounding. For every case you pick one or more controls who are identical or close on named variables — age, sex, year of presentation, same hospital — so that those variables cannot produce a difference between the groups by construction.

Matching is a decision that charges interest, though. Once the data are matched, people inside a matched set are no longer independent of one another, and ordinary logistic regression assumes every observation is independent. Feeding matched data to glm(..., family = binomial) throws the matching away entirely.

Conditional logistic regression instead compares only within a matched set, never across sets. Technically it conditions each set’s own intercept — “how likely anybody in this set was to be a case at all” — out of the likelihood, which is where the name comes from.

A matched set with MM controls contributes the probability that, of everyone in the set, it was this particular person who turned out to be the case:

Li(β)=exp(βxi,case)jset iexp(βxij)L_i(\beta) = \frac{\exp(\beta^{\top} x_{i,\text{case}})} {\displaystyle\sum_{j \in \text{set } i} \exp(\beta^{\top} x_{ij})}

That one expression explains three separate things further down this page, so it is worth memorising its shape: the numerator holds only the case, the denominator holds the whole set, and the set’s own identity appears nowhere in it.

The example on this page

datasets::infert is a matched case-control study of secondary infertility. It ships with base R, so there is nothing to install: 248 rows in 83 matched sets, exactly one case per set, matched on age, parity and education. The exposures are the number of spontaneous abortions (spontaneous) and the number of induced abortions (induced).

The same dataset carries the case-control studies chapter. That chapter is about the design; this page is only about the model.

library(survival)
data(infert)

# The correct model: the stratum IS the matched set
cond <- clogit(case ~ spontaneous + induced + strata(stratum), data = infert)
summary(cond)

# The wrong model: identical right-hand side, matching simply discarded
naive <- glm(case ~ spontaneous + induced, data = infert, family = binomial)
exp(cbind(OR = coef(naive), confint.default(naive)))

# Put a matching variable back in and watch what happens
clogit(case ~ spontaneous + induced + age + parity + strata(stratum), data = infert)

Verified with R 4.6.0 and survival 3.8.6. clogit() lives in the survival package and calls coxph() internally, which is why its output looks like a survival analysis. That is the implementation, not a typo.

What happens when the matching is ignored

The two models carry identical right-hand sides. The only difference is whether strata(stratum) is present. That is what makes the comparison clean: any difference can be attributed to honouring the matching, and not to having added a covariate.

Forest plot on a logarithmic odds-ratio axis with a dashed vertical line at 1. Four estimates, top to bottom. Spontaneous abortions, conditional estimate 7.29 (3.65 to 14.54), a blue square. The same variable with the matching ignored, 3.31 (2.19 to 5.01), a red triangle sitting clearly to the left of the blue square, that is on the side closer to 1. Induced abortions, conditional estimate 4.09 (2.02 to 8.30), a blue square. The same variable with the matching ignored, 1.52 (1.02 to 2.27), again a red triangle to the left, with its lower confidence limit almost touching 1. Both pairs point the same way: ignoring the matching moves the estimate towards 1.
One dataset, one right-hand side, and the only difference is the stratum term. Ignoring the matching (triangles) moves both estimates towards 1.Plotting script figures/scripts/B2-10-conditional-logistic.R
VariableConditional ORMatching ignoredRatioConditional SESE, matching ignored
Spontaneous abortions, per one more7.2853.3112.200.3520.212
Induced abortions, per one more4.0921.5192.690.3610.206

The OR for spontaneous abortions falls from 7.285 to 3.311 — more than halved, and in the direction of 1. Induced abortions move the same way (4.092 to 1.519). The direction is not an accident: matching makes cases and controls resemble one another on the matching variables, so pooling them as if they were independent samples dilutes the association between exposure and outcome.

What strata() actually does

Go back to that likelihood. Read it as a contest: every member of the set is given a score of exp(βx)\exp(\beta^{\top}x), and the expression asks for the probability that, with the scores distributed that way, the case is the one who was picked.

If everybody in a set has identical exposures, everybody has the same score, and that probability is 1/(M+1)1/(M+1) no matter what β\beta is. Such a set contributes a constant to the likelihood, so its contribution to the estimate is 0 — not “a little”.

This is directly measurable. Under the main model on this page (spontaneous + induced, both counts), a set contributes nothing only when every member shares the same pair of counts. Of the 83 matched sets, 7 qualify; the remaining 76 sets (228 rows) are what actually drives the estimate.

Delete those 7 sets entirely and refit:

VariableCoefficient, all 83 setsCoefficient, 76 sets onlySE, all setsSE, those sets only
spontaneous1.9858761.9858760.35240.3524
induced1.4090121.4090120.36070.3607

The largest discrepancy is 1.1e-15 for the coefficients and 5.6e-16 for the standard errors — floating-point machine precision, not a real difference. Those 7 sets never entered the answer.

The figure below does not show the main model. It shows a simplified version that can be drawn: clogit(case ~ spont_any + strata(stratum)). That differs from the main model in two ways — the exposure is collapsed to binary (ever versus never had a spontaneous abortion), and induced is not in the model at all. The condition is looser, so more sets qualify as identical: 28 identical within themselves and 55 varying. The principle is the same; this version is merely drawable (a box is filled or it is not), whereas counts are not. Under that simplified model, all sets and the varying sets alone both give a coefficient of 1.653873.

A two-panel figure. The left panel draws six real matched sets from infert, one per row, each row a case box followed by two control boxes; a filled box means that person had at least one spontaneous abortion. In the first three sets (numbered 1, 4 and 5) the fill is not the same for everyone in the set, and they are annotated informative on the right. In the last three (numbered 2, 3 and 6) the whole set has the same fill — two sets entirely unfilled and one entirely filled — and they are annotated, in a faded colour, cancels out. Below the left panel: 55 of 83 sets vary within themselves, together with the coefficient from all sets, 1.6539, and the coefficient from the varying sets alone, 1.6539 — the two numbers are identical. The right panel is the two-by-two table of the 1:1 pairs: both exposed 17, case exposed only 38, control exposed only 8, neither exposed 20, with only the two off-diagonal cells outlined and highlighted. Underneath it lists b divided by c equals 4.750, clogit OR equals 4.750, McNemar without correction 19.565, clogit score test 19.565, and McNemar with correction 18.283.
Left: a matched set whose members share an exposure contributes nothing, and removing those sets does not move a single decimal place of the coefficient. Right: with 1:1 matching, only the two discordant cells reach the estimate.Plotting script figures/scripts/B2-10-conditional-logistic.R

Matching variables must not go back into the model

This is the easiest mistake to make in a matched analysis and the hardest to catch yourself. Here is what happens when a matching variable is added back:

Added to the modelIts own coefficientIts standard errorCoefficient on spontaneousFitted log-likelihoodWhat R said
ageNA01.98587552-64.20223692nothing at all
parityNA01.98587552-64.20223692nothing at all
educationNA01.98587552-64.20223692nothing at all
age + parity + educationNA01.98587552-64.20223692nothing at all

With no matching variable added, the coefficient on spontaneous is 1.98587552 and the log-likelihood is -64.20223692. Every row of the table above is bit-identical to that: the largest change is 0 in the coefficient and 0 in the log-likelihood. Not “close”. Zero.

The reason is that likelihood again. A matching variable is constant within a set, so its term in exp(βx)\exp(\beta^{\top}x) appears in the numerator and the denominator at the same time and cancels. It has no way to change anything, and the data contain no information with which to estimate it.

1:1 matching and its relationship to McNemar

When the matching is 1:1 (one control per case) and the exposure is binary, conditional logistic regression collapses to something you can compute by hand.

Cross-tabulate each pair by whether the case was exposed against whether the control was exposed:

Control exposedControl not exposed
Case exposed17 (concordant)38 (b)
Case not exposed8 (c)20 (concordant)

The 37 pairs on the diagonal share an exposure and, by the previous section, contribute nothing. The remaining 46 discordant pairs are the entire information content, and the conditional OR is exactly the ratio of those two cells:

OR^cond=bc,χMcNemar2=(bc)2b+c\widehat{\mathrm{OR}}_{\text{cond}} = \frac{b}{c}, \qquad \chi^{2}_{\text{McNemar}} = \frac{(b-c)^{2}}{b+c}

In this dataset 38 divided by 8 is 4.750, and the OR reported by clogit() is 4.750. They differ by 1.8e-8, which is the optimiser’s convergence tolerance rather than a real difference.

Read the other way round, this is also why McNemar alone is usually not enough. It takes one binary exposure, cannot adjust for anything else, and handles neither 1:M matching nor a continuous exposure. Conditional logistic regression does all of those, and in the special case where McNemar applies it returns the same answer.

Common misuses

MisuseWhy it is wrong
Fitting matched data with ordinary logistic regressionMembers of a set are not independent; the estimate moves towards 1 and the p-value will not warn you
Using a change in the p-value to detect a dropped stratum termThe p-value can move either way; only the design documentation is reliable
Putting a matching variable in as a covariateIt is constant within a set, so the coefficient returns NA with no warning whatsoever
Removing strata() because that column came back NAThat reverts to the biased model; the fix is to take the matching variable out
Reporting without checking coef() for NAIt is the only place that tells you a variable was discarded
Assuming that more sets and tighter matching are always betterOvermatching makes the exposure constant within sets, and those sets contribute zero
Quoting the row count as the sample size when discussing powerThe usable information is the number of sets that vary within themselves
Writing “conditional logistic regression equals McNemar” without naming the testOnly the uncorrected McNemar equals the score test, and correction is the default
Stopping at McNemarIt cannot adjust for covariates and handles neither 1:M matching nor continuous exposures
Reading an OR from a matched case-control study as an RRThe denominators were chosen by the investigator; see case-control studies
Splitting 1:M data down to 1:1 so that McNemar can be usedThat discards the other controls; clogit() handles 1:M directly
Adjusting for the matching variables “again, to be safe” at the analysis stageIt is not safer; it just puts an inexplicable empty column in the report

Reproducing every number on this page

/opt/homebrew/bin/Rscript figures/scripts/B2-10-conditional-logistic.R

Read the figure

The answer comes from the same statistical output that produced this page's figures, not from a number typed in beside them.

The same matched data give different odds ratios from conditional logistic regression and from ordinary logistic regression that ignores the matching. What does ignoring it do?

Show the answer and why

Correct answer: It gives 7.29 - the conditional model's value, and ignoring the matching drags the estimate to less than half of it

The conditional model gives 7.29 and ordinary logistic regression 3.31, losing more than half. Ignoring the matching is not merely adjusting for less: the matching variables determine who was selected as a control, so ignoring them ignores the selection mechanism, and the estimate is pulled towards one. 4.09 is a different term in the conditional model (per induced abortion), not the same contrast. In a matched study the matching is part of the design, and the analysis has to follow it.

In 7 of the 83 matched sets every member has the same exposure. What do those sets contribute to the conditional logistic estimate?

Show the answer and why

Correct answer: Those 7 sets contribute nothing - the conditional likelihood reduces to a constant for them

The 7 sets with no within-set variation add only a constant to the conditional likelihood, which is the same as not being there - conditional logistic regression runs on the 76 sets that do vary. 83 is the total, and using it as the effective sample size overstates how many parameters these data can carry. This is why "a couple of hundred records" is not a statement about effective sample size in a matched study: what counts is discordant sets, not rows.

Once each set is reduced to one case and one control, which pairs does McNemar's test actually use?

Show the answer and why

Correct answer: The discordant pairs, 46 of them - only pairs whose members differ in exposure carry the estimate

McNemar's test, and the paired odds ratio, run entirely on the 46 discordant pairs. However many concordant pairs there are - 37 here - they leave the estimate untouched and only inflate the apparent sample size; power depends on the discordant count, not on the 83 pairs in total. When a matched study reports a large n, the question to ask is how many of those pairs were discordant.

Sources and licences

This page is original writing

Report a content problem

The statistics on this site are written by AI and reviewed by AI; a human only spot-checks. What you can see may be what we cannot.

The more specific, the more fixable — e.g. which sentence disagrees with which textbook or paper.

Needed only if you want a reply; reports without it are still read.

Sent along with your report

These are attached automatically. You can drop any of them.