Inverse probability of treatment weighting
How weighting uses the same propensity score to construct a hypothetical population, which clinical question each of ATE, ATT and ATO answers, where extreme weights come from and what truncation and stabilisation each cost, and why keeping everybody makes weighting more sensitive to how the score was modelled.
What this page answers
Propensity score matching used a single score to solve the problem of adjusting for a dozen covariates at once, but it charged a price: the people who could not be matched were thrown away. The example on that page discarded part of the exposed group, and also every control that went unmatched — of 188 controls, only 91 (48.4%) reached the final analysis.
Inverse probability of treatment weighting (IPTW) does something else with the same propensity score: nobody is dropped; everybody gets a weight instead. All the information stays in the analysis, and — this is the more fundamental advantage over matching — it can estimate things matching cannot, including the average effect in the whole population, and the effect of an exposure that changes over time (the foundation of marginal structural models).
The price is a greater sensitivity to how the propensity score was specified. Matching uses only the score’s ordering (who is nearest to whom); weighting uses its value (the value goes in the denominator). A score that is off by a couple of hundredths may make no difference at all to matching, and may create a person with a weight of fifty for weighting.
What weighting does: constructing a hypothetical population
The intuition runs like this. A patient with a propensity score of only 0.1 who nevertheless received the exposure is a rare kind of person; in the data they stand for “many people like me who did not receive it”. So we give them a weight of , letting that one person represent ten.
Do this for everyone and you get a weighted, hypothetical population in which receiving the exposure is unrelated to the covariates — in other words, a population that looks like a randomised trial.
The ATE (average treatment effect) weight is:
is whether the person was exposed and is their propensity score. The exposed are divided by their probability of being exposed, the unexposed by their probability of not being. The formula is one line, and its meaning is worth a pause: each person is inflated into “the whole group of people with the same covariates”, so the same group of people appears simultaneously in the weighted exposed arm and the weighted control arm. That is why the ATE asks what would happen if everyone were treated versus if nobody were.
The example, and the code
We stay with the patients and the propensity score model from the previous page (287 patients, 99 exposed, 47 events, 12 covariates). Using the same data is deliberate: any difference between matching and weighting must therefore come from the method itself.
Those 287 are the patients with complete covariates out of the original cohort of 316; the other 29 were excluded before the door (that step is described on the previous page). This deserves to be said plainly on a page that advertises not dropping anyone: when IPTW says it drops nobody, it means the weighting stage within the analysis set drops nobody. What decides who gets into the analysis set is missing covariate data, a step that happens earlier and that weighting cannot touch at all — for that you need the methods on the missing data page.
library(medicaldata); library(survival)
data(blood_storage, package = "medicaldata")
d <- blood_storage
d$treat <- as.integer(d$RBC.Age.Group == 3)
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)]), ]
e <- fitted(glm(reformulate(covs, "treat"), data = cc, family = binomial()))
tt <- cc$treat
p <- mean(tt) # overall proportion exposed
# -- Four sets of weights, each one line of arithmetic --------------------
w_ate <- tt / e + (1 - tt) / (1 - e) # everyone treated vs nobody
w_att <- tt + (1 - tt) * e / (1 - e) # for those actually treated
w_ato <- tt * (1 - e) + (1 - tt) * e # for those where it is a close call
w_stab <- tt * p / e + (1 - tt) * (1 - p) / (1 - e) # stabilised: marginal probability on top
# Truncation: pull the most extreme 1% and 99% back to the thresholds
q <- quantile(w_ate, c(0.01, 0.99))
w_trunc <- pmin(pmax(w_ate, q[1]), q[2])
# -- Effective sample size: the less even the weights, the further from n --
ess <- function(w) sum(w)^2 / sum(w^2)
c(treated = ess(w_ate[tt == 1]), control = ess(w_ate[tt == 0]))
# -- A weighted model always needs a robust variance ----------------------
coxph(Surv(TimeToRecurrence, Recurrence) ~ treat,
data = cc, weights = w_ate, robust = TRUE)Verified with R 4.6.0 + survival 3.8.6 + medicaldata 0.2.0; every weight is computed from its definition in base R
import numpy as np, statsmodels.api as sm
from lifelines import CoxPHFitter
bs = sm.datasets.get_rdataset("blood_storage", "medicaldata").data
bs["treat"] = (bs["RBC.Age.Group"] == 3).astype(int)
covs = ["Age", "AA", "FamHx", "PVol", "TVol", "T.Stage", "bGS",
"PreopPSA", "PreopTherapy", "Units", "sGS", "AnyAdjTherapy"]
cc = bs[["TimeToRecurrence", "Recurrence", "treat"] + covs].dropna().copy()
e = sm.Logit(cc["treat"], sm.add_constant(cc[covs])).fit(disp=0).predict()
t, p = cc["treat"].to_numpy(), cc["treat"].mean()
w_ate = t / e + (1 - t) / (1 - e)
w_att = t + (1 - t) * e / (1 - e)
w_ato = t * (1 - e) + (1 - t) * e
w_stab = t * p / e + (1 - t) * (1 - p) / (1 - e)
ess = lambda w: w.sum() ** 2 / (w ** 2).sum()
print(ess(w_ate[t == 1]), ess(w_ate[t == 0]))
cc["w"] = w_ate
CoxPHFitter().fit(cc[["TimeToRecurrence", "Recurrence", "treat", "w"]],
duration_col="TimeToRecurrence", event_col="Recurrence",
weights_col="w", robust=True).print_summary()The Python side is the same four lines of arithmetic; lifelines' CoxPHFitter takes weights_col, and will remind you to add robust=True.
Three sets of weights, three questions
| Estimand | Weight | The clinical question | Who the weighted sample represents |
|---|---|---|---|
| ATE | If everyone received this treatment rather than nobody, what is the average difference | The original whole population | |
| ATT | For the people actually treated, how much better is treatment than none | The treated group’s population | |
| ATO | For the people in whom the decision is genuinely difficult, what is the difference | The overlap region in the middle of the score |
These are not three answers of differing precision to one question; they are three different questions. When the effect varies with patient characteristics, their true values differ to begin with. Which one is right depends on what decision the number has to support:
- Health policy asks “what happens if we roll this out” → ATE
- The clinic asks “these patients already on the drug — were they right to be?” → ATT (this is what matching gives you by default)
- A guideline has to handle “the grey zone where both options are defensible” → ATO
figures/scripts/B6-03-iptw.R| Weighting | Estimand | HR | 95% CI | Max weight | ESS (exposed / control) | Max |SMD| |
|---|---|---|---|---|---|---|
| Unweighted (crude) | -- | 1.02 | 0.57–1.84 | 1.00 | 99 / 188 | 0.156 |
| IPTW, ATE | ATE | 1.07 | 0.59–1.94 | 4.30 | 95 / 185 | 0.017 |
| IPTW, stabilised ATE | ATE | 1.07 | 0.59–1.95 | 1.67 | 95 / 185 | 0.017 |
| IPTW, ATE truncated 1/99% | ATE | 1.07 | 0.59–1.94 | 4.07 | 95 / 185 | 0.020 |
| IPTW, ATT | ATT | 1.20 | 0.66–2.21 | 1.56 | 99 / 166 | 0.043 |
| Overlap weights, ATO | ATO | 1.13 | 0.62–2.06 | 0.77 | 97 / 180 | 0.000 |
Extreme weights
In this dataset the propensity scores run from 0.125 to 0.613, far from both 0 and 1, so the largest ATE weight is only 4.30 — which is behaving so well that you cannot see where the problem would be.
Extreme weights do not come from the data so much as from how the propensity score model was specified. Refit the same data with a saturated model (all pairwise interactions among six covariates, 28 parameters for 287 people) and the scores are immediately pushed out to 0.032 and 0.853, with the maximum weight jumping to 12.3.
figures/scripts/B6-03-iptw.RThere are two standard remedies:
Stabilised weights replace the numerator of 1 with the marginal probability ( for the exposed, for the controls). This does not change the expectation of the estimate, but it pulls the mean weight back to around 1 and shrinks the variance considerably — here the maximum weight falls from 4.30 to 1.67 while the HR barely moves (1.07 → 1.07). Stabilisation has no real cost, so it should be the default.
Truncation pulls weights above some percentile back to a threshold. This dataset is truncated at the 1st and 99th percentiles, at 1.29 and 4.07, affecting 6 people. It reduces variance but introduces bias — the people being pulled down are the rarest covariate combinations in the data, and cutting their representation means you are no longer estimating for the original population. The thresholds must be fixed in advance, reported, and varied in a sensitivity analysis.
Balance after weighting
As with matching, the one thing to check after weighting is balance, judged the same way by |SMD| below 0.1, and again never by a p-value. The difference is that here the means and standardised differences have to be computed with the weights applied.
| Covariate | Unweighted | ATE weights | ATT weights | ATO weights |
|---|---|---|---|---|
| Age (years) | -0.135 | 0.001 | -0.007 | 0.000 |
| African American | 0.045 | -0.010 | -0.005 | 0.000 |
| Family history | 0.156 | 0.010 | 0.000 | 0.000 |
| Prostate volume (g) | -0.132 | -0.010 | -0.004 | 0.000 |
| Tumour volume (grade) | -0.104 | -0.004 | -0.017 | 0.000 |
| T stage | -0.019 | -0.002 | 0.008 | 0.000 |
| Biopsy Gleason score | -0.003 | -0.014 | 0.011 | 0.000 |
| Preoperative PSA | 0.026 | 0.002 | 0.002 | 0.000 |
| Preoperative therapy | 0.011 | -0.009 | 0.043 | 0.000 |
| Units transfused | -0.010 | 0.017 | -0.014 | 0.000 |
| Surgical Gleason score | -0.017 | 0.001 | -0.036 | 0.000 |
| Any adjuvant therapy | 0.147 | -0.001 | -0.018 | 0.000 |
Unweighted, 5 covariates exceed 0.1; all three sets of weights bring that to zero, and the ATO column is zero throughout.
figures/scripts/B6-03-iptw.RDrawn rather than tabulated, two things stand out. The ATO points sit exactly on zero — that is an algebraic guarantee, not luck — and the covariates that started furthest from balance are not all pulled back by the same amount.
Note that this checks only the 12 variables that went into the propensity score model. A variable not in the model is not balanced by it, and however beautiful the balance table looks it will never tell you so — this is the concrete local version of the point made on the DAG page.
Three assumptions, three names
Weighting delivers a causal effect on the strength of three assumptions. They appear by name in almost every Methods section, and this page has in fact already covered all three — it just has not named them.
Exchangeability — conditional on the measured covariates, who gets treated is independent of the counterfactual outcomes, which is to say there is no unmeasured confounding. Randomisation buys it outright; an observational study can only assume the conditional version, and that assumption cannot be tested against the data. To quantify what a violation would cost, see the E-value page.
Positivity — every covariate pattern must have a non-zero probability of each treatment. The extreme weights discussed above are its clinical face: a weight blows up precisely because people like that almost never receive that treatment, so the model has to let a handful of them stand in for a whole stratum. Two violations are worth telling apart: random ones (the sample is too small, more people would help) and structural ones (that kind of patient cannot receive that treatment by definition, and no sample size fixes it). ATO is interesting exactly because it sidesteps the problem from a different direction — not by repairing the weights, but by redefining the population being asked about to the region where overlap is best.
Consistency — the outcome observed for someone who received a treatment is their counterfactual outcome under that treatment. It sounds like a tautology, but it demands that the treatment be defined sharply enough. Exposures like “exercise”, “weight loss” or “early intervention” have many versions, and when versions differ in effect the estimand has no single meaning — which is why target trial emulation insists on writing the intervention down as something executable.
A way to keep them apart: exchangeability is about whether a comparable control exists in principle, positivity about whether one actually exists in your data, and consistency about what it is you have estimated the effect of.
Effective sample size
After weighting, “how many people” is no longer the number of rows. The effective sample size (ESS) is defined as:
With perfectly even weights it equals the actual count, and the more uneven the weights the faster it falls. Under this dataset’s main-effects ATE weights the exposed group’s ESS is 95.0 (against 99 actual people) and the control group’s is 185.1 (against 188) — very little loss. Under the saturated model the exposed group’s ESS drops to 80.2.
The ESS should be reported alongside the HR. It is the only clue a reader has for judging whether the width of a confidence interval makes sense: an analysis with an impressive nominal n but an ESS in the dozens is as unstable as a genuinely small study.
Variance after weighting
Weighting means each row is no longer one independent observation — the weights are themselves estimated, and one person has been inflated into several. Fitting an ordinary model underestimates the variance. The standard approach is a robust (sandwich) variance: in R, coxph(..., weights = w, robust = TRUE), or a bootstrap that re-estimates the propensity score model as well (bootstrapping only the outcome model misses the uncertainty in estimating the score).
Every confidence interval in the tables on this page comes from a robust variance.
Weighting or matching
| Matching | Weighting | |
|---|---|---|
| Who stays in the analysis | Only those who could be matched | Everybody |
| Default estimand | ATT | Chosen by the weight (ATE / ATT / ATO) |
| Sensitivity to PS model specification | Lower (only the ordering is used) | Higher (the score is in the denominator) |
| When overlap is poor | People are dropped, and you can see it | Extreme weights appear, and you will not see them unless you look |
| Diagnostics | Balance table, love plot, number dropped | Balance table, weight distribution, ESS |
| Can it handle a time-varying exposure | Very hard | Yes (marginal structural models) |
| Explaining it to a clinical colleague | Easy (“matched to patients with similar characteristics”) | Harder |
How to write up the result
All six weighting schemes produce confidence intervals that cross 1. The correct wording is: in this cohort, no association was detected between red-cell storage age and biochemical recurrence, together with the interval to show the range of uncertainty.
The ATT point estimate (1.20) may not be selected for reporting because it looks more “striking” than the ATE (1.07). Their confidence intervals overlap heavily, both cross 1, and they answer different questions — in this dataset the differences between estimands are the size of noise, and should not be read as a clinical signal.
Common misuses
| Misuse | Why it is wrong |
|---|---|
| Reporting an HR without saying whether it is ATE, ATT or ATO | The three answer different clinical questions, and their values may legitimately differ |
| Not reporting the weight distribution and the maximum weight | Extreme weights are this method’s one major failure mode; a reader who cannot see them cannot judge |
| Not reporting the effective sample size | Nominal n and ESS can differ several-fold, and nothing else explains the width of the interval |
| Using unstabilised weights without saying so | Stabilisation costs almost nothing, so not using it needs a reason |
| Choosing the truncation threshold after seeing the result | It is a choice that changes the population being estimated; fix it in advance and report it |
| An ordinary variance after weighting | Weights make the observations non-independent, and the variance is underestimated |
| Bootstrapping the outcome model only | The uncertainty in the propensity score model itself is never counted |
| Selecting the PS model by AUC | The criterion is balance after weighting, not predictive ability |
| Claiming no confounding because the balance table looks good | Only variables that went into the model are balanced |
| Treating a saturated PS model as “more thorough adjustment” | In a small sample it manufactures extreme weights, and a few people dominate the estimate |
| Writing a non-significant result as “the two groups are the same” | All you may say is that this study did not detect a difference |
Reproducing every number on this page
/opt/homebrew/bin/Rscript figures/scripts/B6-03-iptw.RRead the figure
The answer comes from the same statistical output that produced this page's figures, not from a number typed in beside them.
In the overlap-weight row, the largest absolute standardised mean difference prints as zero. How should that cell be read?
Show the answer and why
Correct answer: It is 0.000, and not because of rounding — where the propensity score comes from a logistic model, this is an identity
By construction, overlap weights make the weighted mean of every covariate in the propensity score model exactly equal across the two groups; the residue the software prints is floating-point rounding, orders of magnitude below any statistical imbalance. So the 0.000 is neither a rounding artefact nor a lucky dataset. The 0.017 is the maximum in the ATE column and the 0.043 the maximum in the ATT column: both sit below the threshold, neither is zero, and the difference between them and 0.000 is one of kind rather than degree. The cost is written elsewhere — the ATO target population is chosen by the data, the people in the middle of the propensity score, and cannot be specified in advance, so the paper has to say who the number refers to.
Swap the propensity score model for a saturated one (28 parameters for 287 people) and the largest weight jumps from 4.30 to 12.3. Which sentence describes what happened to the point estimate?
Show the answer and why
Correct answer: The saturated model's hazard ratio is 1.01, near enough the main-effects ATE — what got eaten was precision, not the point estimate
The saturated model gives 1.01 and the main-effects ATE gives 1.07, so the two point estimates barely differ; what differs is precision — the effective sample size in the exposed group drops noticeably and the interval widens with it. The 1.96 is the upper limit of the saturated model's interval rather than its point estimate, and reading an interval endpoint as an estimate yields a conclusion like doubled risk. Nor is it true that weights stay out of the point estimate: every person's contribution is multiplied by their weight, concentrated weight is perfectly capable of moving it, and it did not here only because of how those few people's outcomes happened to fall — which you cannot know without computing it. Extreme weights are a diagnostic, not a conclusion.
Effective sample size equals the actual count when weights are perfectly even and falls faster the more uneven they get. Why should it be reported next to the hazard ratio?
Show the answer and why
Correct answer: Because the nominal count cannot show dilution — here the exposed group's effective sample size is 95.0, barely diluted, but only this number tells you whether the interval is a reasonable width
Under the main-effects model the exposed group's effective sample size is 95.0 against 99 actual people, so dilution is slight. Under the saturated model the same group falls to 80.2 — not one person left the dataset, yet nearly twenty people's worth of information vanished and the interval widened to match. So this is not a number that makes no difference either way: it is information the nominal count cannot carry, and 95.0 is worth printing precisely because it is allowed to differ from 99. As for choosing a propensity score model, the criterion has always been balance after weighting, not effective sample size and not predictive performance — choosing on effective sample size picks the model that squeezes the imbalance least.
Stabilising the weights takes the largest from 4.30 to 1.67 and barely moves the hazard ratio; truncation pushes weights beyond the 1st and 99th percentiles back to the threshold, touching six people. What separates the two?
Show the answer and why
Correct answer: The unstabilised ATE is 1.070; stabilising leaves the estimate's expectation alone, while truncation changes the population the estimate refers to
Stabilising replaces the numerator of one with the marginal probability, shrinking the variance of the weights while leaving the expectation of the estimate alone — the unstabilised ATE is 1.070 and the stabilised one 1.073, a difference at the scale of noise. That is not a change of scale, though: the distribution of the weights really did change and really did narrow; only the expectation stayed put. Truncation is different. The six people pushed down were the rarest combinations in the dataset, and once their representation is cut back, the 1.066 refers to a population that is no longer quite the original one. So stabilisation costs almost nothing and needs no justification; a truncation threshold has to be set in advance, reported, and varied in a sensitivity analysis. Setting it after seeing the results is selective reporting a reader cannot detect from the paper.
Same dataset, same propensity score model, and the ATT point estimate is larger than the ATE. What decides which one the primary analysis reports?
Show the answer and why
Correct answer: The research question — the ATT interval reaches 2.21 and overlaps the ATE interval heavily, so how the numbers look cannot separate these two quantities
The ATT asks whether the people already on the treatment are being treated correctly; the ATE asks what would happen if it were rolled out to everyone. Where the effect varies with patient characteristics the two have different true values, so they are not two precisions of one answer, and asking which is estimated more reliably asks the wrong question — the ATT interval reaches 2.21, the ATE point estimate is 1.07, both intervals cross one and overlap heavily, and on this dataset the difference between estimands sits at the scale of noise. Always reporting the conservative one also grounds the choice in the numbers: which direction counts as conservative is set by the clinical question, and on the next dataset the ATE may be the larger of the two. The right move is to state in advance which estimand the primary analysis targets.
After weighting, every covariate's absolute standardised mean difference is pushed below the threshold. How far does that table's claim reach?
Show the answer and why
Correct answer: As far as the 12 variables that entered the propensity score model being comparable; anything outside it never gets a row
Balance guarantees only that the 12 variables in the propensity score model are comparable across groups after weighting. Variables left out of the model are not balanced by it, and they do not even get a row in the table — this is the DAG page's point that statistical adjustment can only handle what you measured, stated here in weights. The formal name is exchangeability, and no dataset can test it. Variables over the threshold falling to none says something about those 12 variables and nothing about whether confounding is gone; the 47 events are a question of precision, and more events only narrow the interval rather than turning a table covering 12 variables into causal evidence.
Chapters that use this method
Watch next
6.4 – Propensity Scores and Inverse Probability Weighting (IPW)
Estimating Causal Effects: Inverse Probability Weighting
Outcome research: Causal inference & Propensity score II 傾向分數Sources and licences
This page is original writing