AdvancedIndependently reviewed, not yet spot-checked by a human

Propensity score matching

What matching actually does once a dozen covariates have been compressed into one number, who the caliper throws away, why balance is judged by SMD and never by a p-value, why the matched sample is no longer the population you started with, and how the variance has to be computed afterwards.

What this page answers

The cohort study chapter took the most direct route available: put the confounders into the Cox model together. That works well when the covariates are few and the events are many, but it has two limits.

First, it estimates “who gets treated” and “who has an event” inside the same model. Once there are many covariates you no longer know which patients are holding up the treatment coefficient. Two groups may not overlap at all on some covariate, and the model will still extrapolate a number for you along its linearity assumption, without warning.

Second, the number of events decides how many variables you may fit. The Cox model page gives the rule of thumb of about ten events per variable. This dataset has 47 events, which by that standard allows four or five variables — while the list of clinically worthwhile covariates runs to a dozen.

The propensity score addresses exactly that squeeze: compress a dozen covariates into a single number, so that the complexity of “adjustment” is no longer limited by the number of events, only by the number of treated patients.

What a propensity score is

The definition is one sentence: the probability that a person receives the exposure, given their covariates.

e(x)=P(A=1X=x)e(\mathbf{x}) = P(A = 1 \mid \mathbf{X} = \mathbf{x})

In practice it is estimated with logistic regression in which the outcome variable is treatment, not the clinical outcome:

logite(x)=β0+β1x1++βpxp\operatorname{logit} e(\mathbf{x}) = \beta_0 + \beta_1 x_1 + \cdots + \beta_p x_p

It is useful because of a property that is not at all obvious: if a set of covariates suffices to remove confounding, then balancing this one score is enough to balance that entire set across the groups. A balancing problem in 12 dimensions collapses to one dimension. This is the balancing score property.

The worked example

We stay with the cohort from the cohort study chapter: patients undergoing radical prostatectomy who were transfused during surgery, where the exposure is the storage age of the transfused red cells (the oldest group versus short and medium storage) and the outcome is biochemical recurrence. Reusing the cohort is deliberate — one clinical question, answered two ways.

The dataset holds 316 patients. After dropping the 29 with a missing covariate, 287 enter the analysis (99 exposed, 188 controls), of whom 47 had a biochemical recurrence. The propensity score model contains 12 covariates.

Matching by hand, once

The code below is written from scratch in base R: logistic regression for the score, greedy nearest-neighbour matching, SMD computed from its definition. In practice MatchIt does all of this in one line (that line appears later on this page), but someone who has only ever seen that line does not know whom the caliper threw out.

library(medicaldata); library(survival)
data(blood_storage, package = "medicaldata")
set.seed(20260822)

d <- blood_storage
d$treat <- as.integer(d$RBC.Age.Group == 3)      # 1 = longest storage
covs <- c("Age", "AA", "FamHx", "PVol", "TVol", "T.Stage", "bGS",
          "PreopPSA", "PreopTherapy", "Units", "sGS", "AnyAdjTherapy")
cc <- d[complete.cases(d[, c("TimeToRecurrence", "Recurrence", "treat", covs)]), ]

# -- 1. Propensity score: the outcome variable is TREATMENT, not the endpoint --
ps_fit <- glm(reformulate(covs, "treat"), data = cc, family = binomial())
cc$ps  <- fitted(ps_fit)
cc$lps <- qlogis(cc$ps)          # match on the logit scale so the tails do not pile up

# -- 2. Greedy nearest neighbour, 1:1, without replacement, caliper = 0.2 logit SD --
cal  <- 0.2 * sd(cc$lps)
tr   <- sample(which(cc$treat == 1))   # random order: greedy matching is order-sensitive
pool <- which(cc$treat == 0)
pairs <- list()
for (i in tr) {
  if (!length(pool)) break
  dist <- abs(cc$lps[pool] - cc$lps[i])
  m <- which.min(dist)
  if (dist[m] > cal) next              # caliper blocks it: no match, so no pair
  pairs[[length(pairs) + 1]] <- c(i, pool[m])
  pool <- pool[-m]                     # without replacement: a used control leaves the pool
}
matched <- cc[unlist(pairs), ]
matched$pair <- rep(seq_along(pairs), each = 2)

# -- 3. SMD from its definition; the denominator stays the PRE-matching pooled SD --
smd_denom <- sapply(covs, function(v) {
  x <- cc[[v]]; t <- cc$treat == 1
  sqrt((var(x[t]) + var(x[!t])) / 2)
})
smd <- function(dat) sapply(covs, function(v) {
  x <- dat[[v]]; t <- dat$treat == 1
  (mean(x[t]) - mean(x[!t])) / smd_denom[[v]]
})
round(cbind(before = smd(cc), after = smd(matched)), 3)

# -- 4. Effect estimate, with the variance acknowledging the pairs --
coxph(Surv(TimeToRecurrence, Recurrence) ~ treat + cluster(pair), data = matched)

Verified with R 4.6.0 + survival 3.8.6 + medicaldata 0.2.0 (the matching itself uses base R only)

What comes out: 91 pairs, 182 people in total, with 8 exposed patients excluded because no control lay close enough inside the caliper.

Overlap: the figure to look at before matching

Before asking how well the matching went, there is a prior question: do the two groups’ propensity scores overlap at all? Where they do not overlap, no statistical method can supply a comparable control — any estimate there rests on the model extrapolating.

Two back-to-back histograms. On the left, the distribution of propensity scores before matching, exposed above and controls below, with a small cluster of controls in the low-score region that has no exposed counterpart. On the right, after matching, the two distributions are close to mirror images.
Distribution of the propensity score, exposed pointing up and controls pointing down. Left, before matching: the controls have a small cluster at the lowest scores where the exposed group has nobody at all. Right, after matching: the two sides are roughly mirrored.Plotting script figures/scripts/B6-02-psm.R

In this dataset the propensity scores run from 0.125 to 0.613, and the region of common support — the interval where both groups have people — is 0.233 to 0.609. Anyone outside common support is discarded automatically by matching, and that is a genuine advantage of matching over regression adjustment: regression will not tell you it is extrapolating; matching hands you a list of the people it could not match.

Judging balance: SMD, not p-values

Once matching is done, the one thing to check is balance. The criterion is the standardised mean difference (SMD), and by convention |SMD| below 0.1 counts as balanced. The definition of the SMD, why it does not inflate with sample size, and where the 0.1 line came from are covered in full on Table 1 and the standardised mean difference, so they are not repeated here.

One thing is worth stressing: do not run between-group significance tests before and after matching. Matching shrinks the sample, so p-values rise on their own — the sentence “after matching, the difference was no longer significant” holds even when balance did not improve at all. What that test measures is sample size, not balance.

Love plot: absolute standardised mean differences for 12 covariates, circles before matching and triangles after, with a dashed line at 0.1. Most triangles sit closer to zero than their circles, but 4 covariates moved further away after matching.
Love plot. Circles are before matching, triangles after, and the dashed line is the conventional 0.1 threshold. Most variables moved left, but note that 4 of them moved right — matching improves the whole, and guarantees nothing about any single cell.Plotting script figures/scripts/B6-02-psm.R
CovariateSMD beforeSMD after
Age (years)-0.1350.033
African American0.0450.029
Family history0.156-0.026
Prostate volume (g)-0.132-0.002
Tumour volume (grade)-0.104-0.031
T stage-0.019-0.034
Biopsy Gleason score-0.003-0.032
Preoperative PSA0.026-0.015
Preoperative therapy0.011-0.065
Units transfused-0.010-0.067
Surgical Gleason score-0.017-0.014
Any adjuvant therapy0.1470.000

Before matching, 5 covariates had |SMD| above 0.1, the largest being 0.156. After matching, 0 remain above the threshold, the maximum falls to 0.067, and the mean falls from 0.067 to 0.029.

Double robustness: why adjusting again is not double-counting

The previous section said that an important covariate still imbalanced after matching should be adjusted for again in the post-matching model. That advice has a name: double robustness.

Matching and weighting need the propensity score model to be right; the post-matching regression needs the outcome model to be right. Either can be wrong. The doubly robust property is that the estimate stays consistent as long as at least one of the two is correct — you do not have to bet on which one, you hold two tickets and need only one to win.

This is why “do not put covariates back in after matching, that would be adjusting twice” is wrong. Adjusting again costs a few degrees of freedom and buys a second chance at getting it right. In practice it is the default, not a remedy for special cases.

The three choices inside “matching”

Matching is not one action; it is three independent decisions. Here are three configurations on the same data:

ConfigurationExposedControlsExposed droppedMax |SMD|Covariates above 0.1HR95% CI
1:1, caliper 0.2 SD919180.06701.020.51–2.03
1:1, no caliper999900.08701.030.51–2.09
1:2, caliper 0.2 SD76152230.10210.830.40–1.74

What each decision buys:

  • 1:1 or 1:k. When controls are plentiful, 1:k raises the number of events and therefore the precision. But the k-th nearest neighbour is always further away than the first, so the larger k is, the worse the balance — which is what the third row shows: 1:2 pushes the maximum |SMD| past 0.1.
  • The caliper (the matching radius). The convention is 0.2 standard deviations of the logit propensity score (here, 0.067). What it blocks are the exposed cases for whom nobody similar enough exists. The first row discards 8 of them and buys better balance; the second sets no caliper, discards nobody, and ends up with a larger maximum |SMD|. This is a direct trade of bias against sample size.
  • With or without replacement. The code above matches without replacement: a control that has been used leaves the pool. Allowing replacement lets one control serve several exposed patients, which usually improves balance, but the same person is then counted more than once and the variance has to be handled specially — and if a handful of controls are reused repeatedly, the effective sample size falls far below the nominal count.

The last two columns give each configuration’s HR and confidence interval (all with pair-robust variance). They are listed not so that you can pick one, but because this is what the “report all of them” rule demanded in the next section actually looks like: three point estimates from 0.83 to 1.03, with heavily overlapping intervals, all of which cross 1. The one that sits furthest from 1 is 1:2, caliper 0.2 SD (0.83, 0.40–1.74), and it is simultaneously the configuration that discarded the most exposed patients (23) and achieved the worst balance (maximum |SMD| 0.102; covariates past the line: 1) — the configuration whose point estimate moved most is also the one whose sample was replaced most.

The way to read a sensitivity analysis is to see how far the numbers spread, not to choose one of them. Here they do not spread far, but all three intervals are wide enough that a moderate effect cannot be excluded, so the narrow spread does not establish much either.

The matched sample is no longer the population you started with

This is the point most often skipped, and it directly determines how the conclusion may be phrased.

1:1 matching, especially with a caliper, keeps every exposed case for whom a control could be found, plus the controls most like them. So the matched sample represents “people who look like the exposed group”, and the quantity being estimated is the ATT (average treatment effect on the treated), not the ATE for the whole population.

EstimandThe question it asksWhose population
ATEIf everyone were treated versus nobody, what is the average differenceEverybody
ATTFor the people actually treated, how much better is treatment than no treatmentThe treated group
ATOFor the people for whom treating or not is a close call, what is the differenceThe overlap region

When the effect varies with patient characteristics (effect modification) these three differ numerically, and they answer different clinical questions. ATT asks “were these people, already on the drug, right to be on it?”; ATE asks “what would happen if we rolled this out to everyone?”. The inverse probability weighting page shows all three estimands computed on this same dataset.

The model on this page discarded 8 exposed cases, so strictly speaking it is not even the ATT — it is the ATT among the exposed patients who could be matched. That sentence belongs in the limitations, together with the number of people dropped.

Variance after matching

The two rows of a matched pair are not independent — they were put together because their propensity scores were close. In principle that means the variance estimate has to account for the pairing, or the confidence interval will be off. The way to do it is to add cluster(pair) to the Cox model, which switches to a robust (sandwich) variance.

ModelnHR95% CIp
Unadjusted (all patients)2871.020.56–1.850.945
Multivariable Cox (all patients)2871.270.67–2.400.462
After 1:1 matching1821.020.51–2.040.954
After 1:1 matching, pair-robust variance1821.020.51–2.030.954

The four rows of this table are not the same estimand, so do not use the size of the HR to decide which method is better. “Multivariable Cox (all patients)” is a conditional HR in the full sample, given the covariates; “after 1:1 matching” is an HR in the matched sample targeting the ATT. The estimation target and the target population both differ — and on top of that, the Cox HR is non-collapsible, so even with no residual confounding at all, the conditional and marginal values need not agree. A difference between the numbers is not in itself evidence that matching improved the estimate.

The one-line version, with MatchIt

The thirty hand-written lines above are, in practice, this:

library(MatchIt)
m <- matchit(treat ~ Age + AA + FamHx + PVol + TVol + T.Stage + bGS +
               PreopPSA + PreopTherapy + Units + sGS + AnyAdjTherapy,
             data = cc, method = "nearest", distance = "glm",
             caliper = 0.2, std.caliper = TRUE, replace = FALSE)
summary(m)                 # balance table, with SMDs before and after
md <- match.data(m)        # matched data, carrying subclass and weights columns
coxph(Surv(TimeToRecurrence, Recurrence) ~ treat + cluster(subclass), data = md)

MatchIt 4.7.2 produces 92 pairs and an HR of 1.04 (0.51–2.13), against the hand-written version’s 91 pairs and HR of 1.02; the difference is nothing but the random order in which greedy matching processed the exposed cases. The two not agreeing exactly is expected — greedy matching is sensitive to who is handled first, which is why a matching script must always set a seed.

In real work, use the package: it handles optimal matching, full matching, weights for matching with replacement, and a complete set of balance diagnostics. The point of the hand-written version is to let you see what the package is doing, and to know where to look when it gives you something strange.

How to write up the result

All three models put the point estimate near 1, with every confidence interval crossing it. The correct wording is: in this cohort, no association was detected between red-cell storage age and biochemical recurrence.

It may not be written as “storage age is unrelated to recurrence”, and the matched HR of 1.02 may not be described as “an increase in risk” — the interval 0.51–2.03 accommodates substantial benefit and substantial harm at the same time, and with this many events (32 after matching) the data cannot exclude a moderate effect.

Common misuses

MisuseWhy it is wrong
Judging the PS model by its AUCA high AUC means poor overlap; the only criterion is balance after matching
Putting the outcome variable into the PS modelThe PS model’s outcome is treatment; including the endpoint causes overfitting and bias
Testing between groups before and after matchingA smaller sample raises p-values; the test does not measure balance
Reporting overall balance without the per-covariate tableMatching guarantees a close score, not a better value for every covariate
Not reporting how many exposed patients the caliper discardedIt is a silent filter, and it changes the population being estimated
Calling the matched estimate an effect for the whole populationMatching estimates the ATT, and only among those who could be matched
Not inspecting common support after matchingWhere the groups do not overlap, every method is extrapolating
Fitting an ordinary model after matching, ignoring the pairsThe assumption behind the variance estimate is broken, and the fix costs one line
Trying several calipers and reporting the best-looking oneSelective reporting that no reader can detect from the paper
Claiming causation because you matchedA propensity score can only balance the covariates you measured; see B6-01
Leaving a key confounder out of the PS model and calling it adjustedA variable not in the model is not balanced, and matching will not find it for you

Reproducing every number on this page

/opt/homebrew/bin/Rscript figures/scripts/B6-02-psm.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.

Overall balance improves after matching, yet four covariates move the wrong way on the love plot. Which sentence describes those four?

Show the answer and why

Correct answer: The largest absolute standardised mean difference after matching is 0.067, and it belongs to one of the four — greedy matching matches the score, not each covariate

The four covariates that moved the wrong way all sat next to zero before matching, and matching pushed one of them to 0.067 — which is exactly the post-matching maximum. The 0.156 is the pre-matching maximum and belongs to a different covariate, one that matching improved, so calling the four the least balanced to begin with has it backwards. The 0.029 is the post-matching mean: flattering overall, and precisely the number that hides those four. Nor did they move by noise — greedy matching is deterministic, and the same data yields the same pairs every time. Two people with the same score can reach it through different combinations of covariates, so a balance table has to be read row by row in absolute value rather than summarised as balance achieved.

The first row of the table used a caliper and the second did not; the first row is eight exposed cases short. Which sentence describes the difference between the two rows?

Show the answer and why

Correct answer: The largest absolute standardised mean difference with a caliper is 0.067, lower than the row without one, at the cost of eight exposed cases with no close control

The caliper row's maximum is 0.067 and the row without one is 0.087 — the opposite direction from trading balance for sample size. What the caliper bought was the better balance; what it sold was eight exposed cases with no sufficiently similar control. Both values sit below the conventional threshold, so the thing to report here is not which row passes but that those eight people were dropped: that is a selection step, and who they were belongs in the paper. The 0.835 is the hazard ratio from the 1:2 row and belongs to neither of these two. Choosing a matching scheme by how far its point estimate sits from one is what this section warns against: all three intervals overlap heavily and all three cross one, and the scheme whose point estimate moved most is also the one that replaced the most of the sample.

In the matched set the robust standard error is 0.350 and the uncorrected one is 0.354, so the robust one is slightly smaller. Textbooks say ignoring the matched structure understates the variance; this dataset goes the other way. Which sentence describes that?

Show the answer and why

Correct answer: The uncorrected standard error is 0.354, near enough the robust 0.350, and how far apart they land depends on how alike the matched rows are, which the data decides

The size and the direction of the correction depend on how alike the matched rows turn out to be, and that is settled by the data: the covariates in this dataset were already fairly balanced before matching, so the within-pair correlation matching could create is limited and 0.354 and 0.350 barely differ. Both wrong options make the same move, promoting a result from one dataset into a rule. Whether ignoring the structure overstates the variance, and whether the step can be skipped, are both things you learn only by computing the robust variance — using that computation to argue it was unnecessary is circular. On data where the two groups differ more, the same line of code changes the answer materially, and you do not know in advance which case you are in. It costs one line.

The 1:1 match with a caliper drops some of the exposed. Who does the estimate from the matched sample refer to?

Show the answer and why

Correct answer: The 91 exposed cases who remain are the target population, so the estimate refers to the exposed who could be matched

Matching keeps every exposed case that could be matched, plus the controls most like them, so the matched sample stands for the people who look like the exposed. Some exposed cases were dropped here because the caliper found nobody close enough, so strictly this is not even the average effect among the treated but the version restricted to those 91 — a sentence for the limitations, along with the number dropped. The dropped exposed cases are exactly the ones with no available control, so excluding them is the step that narrows the target population rather than a technical detail beside it. The 97 is the number of controls dropped: how many controls fall away does not decide who the estimate refers to, and how many exposed fall away does.

On one dataset the unadjusted hazard ratio is 1.02, the multivariable Cox model gives 1.27, and 1:1 matching gives 1.02. Which sentence describes those three numbers side by side?

Show the answer and why

Correct answer: The adjusted interval reaches 2.40, all three intervals cross one, and the differences among these numbers sit at the scale of noise

All three point estimates sit near one and every interval crosses it, with the adjusted interval reaching 2.40. More fundamentally these rows are not the same estimand: the multivariable Cox model gives a hazard ratio conditional on the covariates, the matched analysis targets the treated, and because the hazard ratio is non-collapsible the two need not agree even with no residual confounding. The p value of 0.46 is smaller than the unadjusted one, but both are far from significant, and reading smaller as pushed out an association treats a difference that never reached statistical significance as a signal. The 1.02 recurring across two methods is not corroboration either: they use the same people and the same outcome, and this dataset has too few events to rule out a moderate effect.

Propensity scores in this dataset run from 0.125 to 0.613, and the region of common support runs from 0.233 to 0.609. What happens to people outside that region?

Show the answer and why

Correct answer: The lower edge of common support is 0.233; matching drops anyone outside it, while regression adjustment keeps them in

Where there is no overlap there is no comparable control, and every method can only extrapolate there. This is one concrete advantage matching has over regression adjustment: the people who cannot be matched are listed and dropped where you can see them, whereas regression never announces that it is extrapolating, and it does not fill the stretch in either — outside common support, the nearest control is precisely somebody who is not similar enough, which is what a caliper exists to prevent. The 0.336 is the control mean; two means being close does not make two distributions overlap, since overlap is a question about the tails, which is what the back-to-back histogram is for. The 0.125 sits below the lower edge of 0.233, and that stretch is where controls exist and no exposed person does.

Watch next

資料小探 – 傾向分數配對法
繁中資料科科講· 4 minThe shortest Traditional-Chinese introduction; four minutes to build a mental picture before reading this page.
Propensity scores: Everything you need to know in 5min
ENMichael Fralick· 7 minAn overview in a clinical context, clear on which part of randomisation a propensity score is imitating.
How Propensity Scores Work | NEJM Evidence
ENNEJM Group· 5 minNEJM's own animated version — good for explaining the idea to a classmate.
Propensity score matching: an introduction
ENBen Lambert· 9 minFrom an econometrics background, and it pushes the argument for why one score suffices to balance all the covariates further than the clinical channels do.
Outcome research: Causal inference & Propensity score II 傾向分數
繁中陳冠甫(長庚)· 64 minA full lecture in Traditional Chinese; every section of this page has a longer version in it.

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.