AdvancedIndependently reviewed, not yet spot-checked by a human

Brier score, NRI and IDI

All three scores exist to answer the same question — is the new model better than the old one? The Brier score folds discrimination and calibration into one number, has no scale of its own, and is simply wrong if you compute it directly on censored survival data. The NRI compresses improvement into a sum of two proportions, at the cost of a sign that depends on which cut-points you picked. This page computes all three, plus the decision curve, on one pair of models and one set of patients, and lets them contradict each other.

What these three scores add to the C-index

The C-index only looks at ranking. Calibration only looks at the scale. Once both have been checked, a paper usually reports three more numbers:

  • Brier score — one overall score that mixes discrimination and calibration together
  • NRI (net reclassification improvement) — how many patients the new model moves into the right band
  • IDI (integrated discrimination improvement) — how much further apart the mean predictions of the two outcome groups have been pulled

All three are computed here on exactly the same two models and the same patients as the decision curve page: developed on survival::rotterdam (2982 patients, 1713 events), validated on survival::gbsg (686 patients, 299 events), horizon 5 years.

ModelPredictorsC-index95% CI for the C-indexMean predicted 5-year risk
A: eight predictors, carried over as published80.66170.628 to 0.69543.1%
B: four predictors, recalibrated in this cohort40.64160.605 to 0.67951.3%

Model A has the higher C-index by 0.020, but it was never recalibrated: it predicts 43.1% on average, where this cohort actually runs at 50.8% — it underpredicts systematically. Every tension on this page grows out of that.

The Brier score: two things inside one number

The Brier score is the mean squared error between predicted probability and observed outcome:

BS=1ni=1n(p^iyi)2\mathrm{BS} = \frac{1}{n}\sum_{i=1}^{n}\bigl(\hat{p}_i - y_i\bigr)^2

yiy_i is 0 or 1 and p^i\hat{p}_i is the model’s probability. Lower is better; the range is 0 to 1.

It decomposes into a calibration term and a discrimination term (the calibration-refinement decomposition of DeGroot and Fienberg 1983; Murphy 1973 is the three-term version, which carries an extra uncertainty term that depends only on the event rate). So a Brier score that improves may mean better ranking, or merely a corrected scale — the number alone cannot tell you which. And it has no scale of its own. Is 0.228 good or bad? The only way to answer is against a reference. The reference used here is written into the stats file: hand every patient this cohort’s own Kaplan-Meier 5-year risk of 50.8%. A model that cannot beat that has told the clinic nothing it did not already know from the base rate.

Computing the Brier score directly on censored data is wrong

The awkward part of a 5-year risk model is that some patients were never followed for five years. In this cohort, 280 of 686 were censored before the 5-year mark, or 40.8%. The remaining 406 have a known 5-year status: 285 had the event and 121 did not.

The intuitive fix is to score only the patients whose status is known. That is complete-case scoring, and it is not the same estimate with more noise — it estimates a different quantity: among the patients who were followed the event rate is 70.2%, while this cohort’s 5-year risk is 50.8%.

The correct approach is IPCW (inverse probability of censoring weighting): estimate the censoring distribution G(t)G(t) with a reverse Kaplan-Meier, then weight everyone who still carries information:

BSIPCW(t)=1ni=1nw^i(t)(p^i(t)yi(t))2\mathrm{BS}^{\mathrm{IPCW}}(t) = \frac{1}{n}\sum_{i=1}^{n} \hat{w}_i(t)\,\bigl(\hat{p}_i(t) - y_i(t)\bigr)^2

Patients with the event before tt get 1/G^(Ti)1/\hat{G}(T_i^-), patients still event-free at tt get 1/G^(t)1/\hat{G}(t), and patients censored earlier get a weight of zero — they are not discarded, they are spoken for by the patients like them who were followed.

On the left, the IPCW Brier score of both models and of the reference prediction at 11 horizons; the horizontal axis is the prediction horizon in years and the vertical axis is the Brier score, lower being better. All three curves rise and then flatten near five years, the two model curves almost overlapping and sitting only slightly below the dashed reference line. On the right, six bars: the left three are model A, model B and the reference under complete-case scoring, the right three are the same under IPCW weighting. In the left group both models sit above their reference; in the right group both sit below it.
Left: the IPCW Brier score recomputed at every horizon. The gap from the reference line is everything either model adds. Right: the same predictions scored two ways. The left half discards the patients censored early, which turns the reference into the event rate among the followed-up — and both models then lose to it.Plotting script figures/scripts/B5-10-brier-nri-idi.R
ScoringModel AModel BReferencePatients scoredVerdict
IPCW weighted0.22820.22720.2499686A beats the reference, B beats the reference
Complete cases only0.25300.22310.2092406A loses to the reference, B loses to the reference

Scaled Brier: a reference gives it a scale

Divide the Brier score by the reference Brier score and subtract from one, and you get the scaled Brier score (also called the Brier skill score):

BSscaled=1BSmodelBSreference\mathrm{BS}_{\text{scaled}} = 1 - \frac{\mathrm{BS}_{\text{model}}}{\mathrm{BS}_{\text{reference}}}

Zero means no better than handing everyone the base rate; one means perfect. This is the number you can actually use to say how much a model adds.

QuantityModel A (eight predictors)Model B (four, recalibrated)
IPCW Brier0.2282 (0.210 to 0.248)0.2272 (0.213 to 0.238)
Scaled Brier0.0866 (0.006 to 0.157)0.0906 (0.044 to 0.148)
C-index0.66170.6416

The C-index favours model A; the Brier score favours model B. The two scaled-Brier intervals overlap heavily, but interval overlap is not an argument — the two estimates come from the same patients, so their errors are almost perfectly correlated and what matters is the interval on the difference itself. Resampled inside the same bootstrap, A minus B is −0.004, 95% interval −0.045 to +0.024, which crosses zero. The defensible statement is therefore that no difference in overall accuracy between the two models was detected in this cohort — not that B is better.

Recomputed at every horizon, which also shows where the estimate stops being trustworthy

The Brier score belongs to one horizon; change the horizon and the answer changes with it:

Horizon (years)Model AModel BReferenceScaled AScaled BAt riskG(t)
10.07820.07630.0773−0.011+0.0136020.958
1.50.13730.13870.1463+0.061+0.0525300.940
20.17550.17660.1894+0.073+0.0684580.895
2.50.20020.20050.2184+0.083+0.0823830.824
30.20420.20700.2296+0.111+0.0983310.751
3.50.21300.21640.2400+0.112+0.0982770.673
40.22190.22320.2465+0.100+0.0952280.595
4.50.22460.22610.2491+0.098+0.0921830.504
50.22820.22720.2499+0.087+0.0911210.359
5.50.21910.21890.2485+0.118+0.119740.233
60.22170.21560.2433+0.089+0.114360.125

The reclassification table: how it is laid out and how to read it

The NRI and the IDI are both built on a reclassification table. Cut the predicted risks into bands, then look at which band each patient falls into under the old and the new model.

The layout is fixed throughout this page: the old model (B) runs down the rows, one row per old band; the new model (A) runs across the columns. Patients on the diagonal are the ones the two models agree about, cells above the diagonal are patients the new model moved up, and cells below it are patients it moved down.

The event group and the non-event group must be tabulated separately. Moving a patient up is the right call for someone who went on to have the event and the wrong call for someone who did not; a single combined table hides who was helped and who was harmed.

These tables are counts, so they can only hold the 406 patients whose 5-year status is known. The 280 censored earlier do not fit into integer cells. That has consequences, and the last section measures them with IPCW weights.

Cut-points 10% / 20%

A generic textbook low/intermediate/high split, carried over without checking it against this cohort.

Had the event by 5 years (n = 285) — old model B ↓, new model A →under 10%10% to 20%20% and overRow total
under 10%0000
10% to 20%0000
20% and over00285285
Moved up / down / unchanged0 / 0 / 285
Still event-free at 5 years (n = 121) — old model B ↓, new model A →under 10%10% to 20%20% and overRow total
under 10%0000
10% to 20%0000
20% and over00121121
Moved up / down / unchanged0 / 0 / 121

Cut-points 15% / 30%

A moderate split, still below the cohort's 5-year risk.

Had the event by 5 years (n = 285) — old model B ↓, new model A →under 15%15% to 30%30% and overRow total
under 15%0000
15% to 30%0000
30% and over030255285
Moved up / down / unchanged0 / 30 / 255
Still event-free at 5 years (n = 121) — old model B ↓, new model A →under 15%15% to 30%30% and overRow total
under 15%0000
15% to 30%0000
30% and over03883121
Moved up / down / unchanged0 / 38 / 83

Cut-points 30% / 60%

The outer pair of the four key thresholds the decision curve on B5-07 is drawn around.

Had the event by 5 years (n = 285) — old model B ↓, new model A →under 30%30% to 60%60% and overRow total
under 30%0000
30% to 60%301700200
60% and over0166985
Moved up / down / unchanged0 / 46 / 239
Still event-free at 5 years (n = 121) — old model B ↓, new model A →under 30%30% to 60%60% and overRow total
under 30%0000
30% to 60%38760114
60% and over0257
Moved up / down / unchanged0 / 40 / 81

Cut-points 50% / 60% (⚠ chosen after seeing the answer)

CHOSEN AFTER SEEING THE ANSWER. Included only to show that a cut-point pair exists that reverses the sign of the NRI on this same pair of models. It is not a clinically motivated split and must not be read as one.

Had the event by 5 years (n = 285) — old model B ↓, new model A →under 50%50% to 60%60% and overRow total
under 50%12800128
50% to 60%5121072
60% and over0166985
Moved up / down / unchanged0 / 67 / 218
Still event-free at 5 years (n = 121) — old model B ↓, new model A →under 50%50% to 60%60% and overRow total
under 50%890089
50% to 60%214025
60% and over0257
Moved up / down / unchanged0 / 23 / 98

How the NRI is computed

Add the net movement of the two tables and you have the categorical NRI:

NRI=nupeventndowneventnevent+ndownnonnupnonnnon\mathrm{NRI} = \frac{n_{\text{up}}^{\text{event}} - n_{\text{down}}^{\text{event}}}{n^{\text{event}}} + \frac{n_{\text{down}}^{\text{non}} - n_{\text{up}}^{\text{non}}}{n^{\text{non}}}

First term: for the event group, moving up is right, so it is up minus down. Second term: for the non-event group, moving down is right, so it is down minus up. Each term runs from −1 to +1, and the sum from −2 to +2.

Two bar charts side by side. The horizontal axis lists the four cut-point schemes, the vertical axis counts reclassified patients, bars above the zero line are patients moved up and bars below are patients moved down. The left panel is patients who had the event by five years, the right panel is patients still event-free. Neither panel has a single upward bar. The leftmost scheme is labelled as having moved nobody in both panels; the other three have downward bars only. In the left panel those bars grow longer towards the right; in the right panel they do not — the third scheme has the longest bar, and the last one, the scheme picked after the fact, is shorter than the two before it. The NRI contribution of each scheme is printed above it.
Where the reclassified patients actually went, for one pair of models under four cut-point schemes. Moving down is wrong for the event group and right for the non-event group, so the very same moves are recorded as harm in one panel and as improvement in the other. Nothing sits above the zero line because the recalibrated model B gives almost every patient a higher risk than model A does.Plotting script figures/scripts/B5-10-brier-nri-idi.R
Cut-pointsEvent termNon-event termNRI95% CIWhere the cut-points came from
10% / 20%+0.000+0.000+0.000+0.000 to +0.000specified in advance
15% / 30%−0.105+0.314+0.209+0.095 to +0.307specified in advance
30% / 60%−0.161+0.331+0.169+0.038 to +0.304specified in advance
50% / 60%−0.235+0.190−0.045−0.148 to +0.102⚠ chosen after seeing the answer

Why the NRI comes out positive here

Notice something first: apart from the scheme in which nobody moved at all, every scheme has a negative event term and a large positive non-event term. That is not a coincidence. It is the direct consequence of model A underpredicting — it pushes almost every patient down a band.

Take the 15/30 scheme. The patients moved down are 30 who had the event and 38 who did not. The first group was harmed (they were going to have the event, and their risk was lowered); the second was helped. The NRI adds the two proportions directly:

  • Event group: 30 out of 285, recorded as −0.105
  • Non-event group: 38 out of 121, recorded as +0.314
  • Sum: +0.209

The cut-points decide everything

One pair of models, one set of patients. Change the cut-points and the NRI runs from +0.000 to +0.209, and the last scheme is negative.

Cut-pointsNRINet benefit difference at the lower cutAt the upper cut
10% / 20%+0.000+0.00+0.00
15% / 30%+0.209+0.00+6.12
30% / 60%+0.169+6.12+3.04
50% / 60% ⚠−0.045−23.55+3.04

The net benefit difference is in net true positives per 1000 patients, model A minus model B, defined exactly as on the decision curve page.

Three things are worth taking one at a time:

The first scheme has an NRI of exactly +0.000, because nobody moved. Look back at its two tables: all 285 event patients and all 121 non-event patients land in the top band under both models. Both cut-points sit below this cohort’s risk distribution, so the scheme asked nothing at all — which is what cut-points carried over from another disease and another population, never checked against the local data, look like.

The last scheme reverses the sign of the NRI, and it was chosen after the answer was known. That scheme carries a chosen_to_demonstrate flag in the stats file, and the marks in the two tables above and the asterisk on the figure are rendered from it. It is left on the page rather than tidied away because this choice is exactly what the page is criticising: when a paper reports one scheme, the reader has no way of knowing how many were tried.

Within one scheme, the NRI and the net benefit need not share a sign. At the lower cut of the 50/60 scheme, model A’s net benefit is lower than model B’s by 23.55 per 1000, while at the upper cut it is 3.04 higher.

On the left, the categorical NRI of each of the four cut-point schemes with its bootstrap confidence interval; the first three sit above the zero line and the last crosses it and carries an asterisk noting that its cut-points were chosen after seeing the answer. On the right, the net benefit difference between the same two models plotted against threshold probability, the vertical axis being net true positives per 1000. The curve hugs zero at low thresholds, crosses it repeatedly through the middle of the range, and reaches its lowest point at the fifty-per-cent threshold.
Left: what the NRI says. Right: what the net benefit says about the same two models. The horizontal axes differ, but both panels describe one thing — how much better A is than B. The left gives a single number; the right gives a whole curve, and the curve changes sign repeatedly.Plotting script figures/scripts/B5-10-brier-nri-idi.R
ThresholdNet benefit, ANet benefit, BA minus B (per 1000)Bootstrap 95% CI
10%0.45370.4537+0.00+0.00 to +0.00
15%0.42160.4216+0.00+0.00 to +0.00
20%0.38540.3854+0.00+0.00 to +0.00
30%0.30380.2977+6.12−24.19 to +35.36
40%0.19250.1966−4.12−49.03 to +47.03
50%0.09820.1218−23.55−67.11 to +25.64
60%0.06470.0617+3.04−40.25 to +31.03

The IDI: no cut-points, but not free either

The IDI drops cut-points entirely and compares the mean predicted risk of the two outcome groups:

IDI=(pˉeventnewpˉeventold)(pˉnonnewpˉnonold)\mathrm{IDI} = \bigl(\bar{p}^{\,\text{new}}_{\text{event}} - \bar{p}^{\,\text{old}}_{\text{event}}\bigr) - \bigl(\bar{p}^{\,\text{new}}_{\text{non}} - \bar{p}^{\,\text{old}}_{\text{non}}\bigr)

Equivalently, it is the increase in the discrimination slope — the mean prediction among events minus the mean prediction among non-events.

QuantityModel A (new)Model B (old)
Mean predicted risk, events48.6%55.0%
Mean predicted risk, non-events36.5%46.9%
Discrimination slope0.12130.0813

The IDI is 0.0400, bootstrap 95% CI 0.0139 to 0.0563. That interval excludes zero, so it can be stated plainly: model A separates the event and non-event groups further than model B does.

The complete-case tables are biased: the IPCW-weighted comparison

Every reclassification table above holds integer counts, so none of them can hold the 280 patients censored early. Recomputing the same NRI and IDI with IPCW weights shows what that costs:

Cut-pointsNRI (complete cases)NRI (IPCW weighted)Difference
10% / 20%+0.000+0.000+0.000
15% / 30%+0.209+0.200−0.009
30% / 60%+0.169+0.166−0.004
50% / 60%−0.045−0.047−0.002

The IDI behaves the same way: 0.0400 on complete cases against 0.0371 weighted.

The gaps are small, but they point the same way and they are not rounding: apart from the scheme that moved nobody at all, where both are exactly zero, the complete-case version is a little more optimistic every time. After weighting the effective sample sizes are 348.701 events and 337.107 non-events, both larger than the 285 and 121 of the integer tables — the missing patients are back, and they pull the answer down.

In this dataset the bias is too small to change any conclusion. Whether it stays small depends on how heavy the censoring is and on whether censoring is related to the predictions, and both are things a paper has to report rather than assume.

Running it yourself

library(survival)
data(cancer, package = "survival")
# The same cohort harmonisation and model fit as B5-05, spelled out so
# this block runs on its own.


H <- 5 * 365.25

rot <- rotterdam
rot$rfs_time  <- pmin(rot$rtime, rot$dtime)
rot$rfs_event <- as.integer(rot$recur == 1 | rot$death == 1)
rot$size_mm   <- c("<=20" = 15, "20-50" = 35, ">50" = 60)[as.character(rot$size)]
rot$grade3    <- as.integer(rot$grade >= 3)

ext <- gbsg
ext$rfs_time  <- ext$rfstime; ext$rfs_event <- ext$status
ext$size_mm   <- ext$size;    ext$grade3    <- as.integer(ext$grade >= 3)

# The two candidate models, defined exactly as this page's figure script does.
BIG   <- c("age", "meno", "size_mm", "grade3", "nodes", "log_pgr", "log_er", "hormon")
SMALL <- c("age", "size_mm", "nodes", "grade3")
rot$log_pgr <- log1p(rot$pgr); rot$log_er <- log1p(rot$er)
ext$log_pgr <- log1p(ext$pgr); ext$log_er <- log1p(ext$er)
keep <- c("rfs_time", "rfs_event", BIG)
dev  <- rot[complete.cases(rot[, keep]), keep]
ext  <- ext[complete.cases(ext[, keep]), keep]

# Breslow cumulative baseline hazard, written out: basehaz(centered = FALSE)
# does not match predict(type = "lp"), which is centred, and pairing them
# leaves every predicted risk short by a constant factor.
breslow_h0 <- function(time, event, lp, h = H) {
  o <- order(time); time <- time[o]; event <- event[o]; r <- exp(lp[o])
  at_risk <- rev(cumsum(rev(r)))
  sum(1 / at_risk[event == 1 & time <= h])
}
form_of <- function(v) as.formula(paste("Surv(rfs_time, rfs_event) ~",
                                        paste(v, collapse = " + ")))
fit_big   <- coxph(form_of(BIG),   data = dev)
fit_small <- coxph(form_of(SMALL), data = dev)
h0_big   <- breslow_h0(dev$rfs_time, dev$rfs_event,
                       as.numeric(as.matrix(dev[, BIG]) %*% coef(fit_big)))
lp_big   <- as.numeric(as.matrix(ext[, BIG])   %*% coef(fit_big))
lp_small <- as.numeric(as.matrix(ext[, SMALL]) %*% coef(fit_small))

# A: eight predictors, exactly as it left development. B: four predictors,
# then recalibrated to this cohort.
pred_A <- 1 - exp(-h0_big * exp(lp_big))
sl_B   <- unname(coef(coxph(Surv(rfs_time, rfs_event) ~ lp_small, data = ext))[1])
h0_B   <- breslow_h0(ext$rfs_time, ext$rfs_event, sl_B * lp_small)
pred_B <- 1 - exp(-h0_B * exp(sl_B * lp_small))


# 1. Censoring distribution: a Kaplan-Meier on the flipped event indicator
Gfit <- survfit(Surv(rfs_time, 1 - rfs_event) ~ 1, data = ext)
G_at    <- function(u) summary(Gfit, times = u, extend = TRUE)$surv
G_minus <- function(u) sapply(u, function(x)          # left limit, for the cases
  summary(Gfit, times = max(0, x - 1e-8), extend = TRUE)$surv)

# 2. IPCW weights. Patients censored early get zero: not discarded, but
#    represented by the patients like them who were followed.
ipcw <- function(d, t) {
  is_case <- d$rfs_time <= t & d$rfs_event == 1
  is_ctrl <- d$rfs_time >  t
  w <- numeric(nrow(d))
  w[is_case] <- 1 / G_minus(d$rfs_time[is_case])
  w[is_ctrl] <- 1 / G_at(t)
  list(w = w, case = is_case, ctrl = is_ctrl)
}

# 3. The IPCW Brier score and its reference
brier_ipcw <- function(pred, t = H) {
  z <- ipcw(ext, t)
  contrib <- numeric(nrow(ext))
  contrib[z$case] <- (1 - pred[z$case])^2
  contrib[z$ctrl] <- pred[z$ctrl]^2
  mean(z$w * contrib)
}
base <- 1 - summary(survfit(Surv(rfs_time, rfs_event) ~ 1, ext),
                    times = H)$surv
1 - brier_ipcw(pred_A) / brier_ipcw(rep(base, nrow(ext)))   # scaled Brier

# 4. The complete-case version, for contrast. Only the `known` line differs.
known <- ext$rfs_time > H | (ext$rfs_time <= H & ext$rfs_event == 1)
y     <- as.integer(ext$rfs_time <= H & ext$rfs_event == 1)
mean((y[known] - pred_A[known])^2)   # the reference becomes the followed-up event rate,
                                     # which is not this cohort's risk

# 5. The NRI: band, count the moves, add the two proportions
band <- function(p, cuts) cut(p, breaks = c(-Inf, cuts, Inf), labels = FALSE)
nri <- function(cuts) {
  a <- band(pred_A, cuts); b <- band(pred_B, cuts)
  ev <- known & y == 1; ne <- known & y == 0
  (sum(a[ev] > b[ev]) - sum(a[ev] < b[ev])) / sum(ev) +   # events: up minus down
  (sum(a[ne] < b[ne]) - sum(a[ne] > b[ne])) / sum(ne)     # non-events: down minus up
}
sapply(list(c(.10, .20), c(.15, .30), c(.30, .60), c(.50, .60)), nri)
# A new answer for every scheme -- a paper reporting one leaves the reader
# unable to tell how many were tried.

# 6. The IDI: no cut-points, but no absolute levels either
ev <- known & y == 1; ne <- known & y == 0
(mean(pred_A[ev]) - mean(pred_B[ev])) - (mean(pred_A[ne]) - mean(pred_B[ne]))

Verified on R 4.6.0 with survival 3.8.6. No extra packages: the point of this page is to write the IPCW weights and the NRI sum out once, and remembering an argument name would not serve that.

Five things to ask when reading a paper

  1. Is there a reference next to the Brier score? Without one it has no scale. At minimum there should be a scaled Brier score, or the score of a model that hands everyone the prevalence.
  2. How was censoring handled? A Brier score reported on survival data with no mention of IPCW is usually complete-case scoring, and that can be wrong down to the sign.
  3. Where did the NRI cut-points come from? Were they specified in advance, clinically motivated, and is one scheme reported? Several schemes with only the best discussed looks identical on paper to one scheme with several tried.
  4. Are the two NRI components reported separately? The sum alone hides an event term that got worse, which is what three of the four schemes on this page do.
  5. Is a decision curve or net benefit reported alongside? The NRI is a unitless sum; net benefit has units and is tied to a trade-off someone had to state out loud.

Common misuses

MisuseWhy it is wrong
Computing the Brier score directly on censored dataComplete-case scoring changes the estimand; on this page it reverses the sign of the conclusion
Reporting a Brier score with no referenceIt has no scale, so the reader cannot tell how much the model adds
Reading an improved Brier score as improved calibrationIt mixes discrimination and calibration; either one can be responsible
Choosing cut-points after seeing the NRIThe same pair of models runs from zero to twenty per cent and then turns negative
Reporting only the NRI totalIt hides components pointing in opposite directions — events harmed, non-events helped
Reading the NRI as “how many more patients were treated correctly”It sums two proportions with different denominators; that sum is nobody’s head count
Reporting an NRI or IDI on a poorly calibrated modelShifting the whole scale is enough to manufacture a positive value with no change in ranking
Using the IDI in place of a calibration plotIt reads only the difference of two means, never whether the absolute levels are right
Drawing conclusions from IPCW estimates late in follow-upWhen G(t) is small a handful of patients dominate the estimate
Comparing NRI values across studiesCut-points, risk distribution and censoring all differ, so the numbers are not comparable

What this page concludes

One pair of models, one set of patients, one 5-year horizon:

  • The C-index favours model A
  • The Brier and scaled Brier scores favour model B
  • The NRI runs from +0.000 to +0.209 across four schemes, and the scheme chosen after the fact gives −0.045
  • The net benefit difference changes sign 10 times across the threshold grid, with intervals that generally cross zero

None of these scores is wrong. They answer different questions, and most of those are not the question the clinic is asking. The clinical question is whether deciding by this model beats current practice, and that one is answered by the decision curve — which presupposes that the model’s scale is right in the first place, the business of the calibration page. The Brier score, the NRI and the IDI belong beside those two as supporting description, not in place of them.

Reproducing every number on this page

/opt/homebrew/bin/Rscript figures/scripts/B5-10-brier-nri-idi.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.

Same predictions, same patients: under IPCW both models beat the reference, and under complete-case scoring both lose to it. Where does the reversal come from?

Show the answer and why

Correct answer: The complete-case reference Brier falls to 0.209, because it is the event rate among those who were followed up, which is not this cohort's five-year risk

The reversal is not in the models, it is in the reference. The complete-case reference is the event rate among those who were followed up, 0.702, so a roughly even-odds cohort is swapped for a high-risk one, the prediction that gives everyone the base rate and says nothing suddenly looks accurate, the reference Brier falls to 0.209, and both real models lose to it. Blaming a model does not work either: model A's complete-case Brier of 0.253 is indeed worse, but in the same table model B gets better - one goes up and one goes down, and the only cell they share is the reference. Nor is this extra noise: discarding four in ten patients estimates a different quantity, not the same one with wider error.

The two models' scaled Brier intervals overlap heavily. Does that establish that there is no difference in overall accuracy between them?

Show the answer and why

Correct answer: No, and what to look at is the interval of the difference itself - its upper bound is 0.024, its lower bound is negative, so it crosses zero

The two estimates come from the same patients, so their errors are almost perfectly correlated and whether the marginal intervals overlap has no fixed relationship to the interval of the difference - the difference has to be resampled inside the same bootstrap and read on its own. That interval has an upper bound of 0.024 and a negative lower bound, so it crosses zero, and the sentence to write is that no difference in overall accuracy between the two models was detected in this cohort. 0.006 is the lower bound of model A's own interval, which speaks to A beating the reference, a separate question from A against B. 0.091 is model B's point estimate, and taking one point falling inside another interval as evidence of equivalence is exactly the move to avoid: claiming equivalence needs a non-inferiority design and a margin set in advance.

The same pair of models and the same patients give four different NRIs under four sets of cut-points. What does that say about a paper reporting one set?

Show the answer and why

Correct answer: A set of cut-points exists that turns the NRI into -0.045, and it was chosen after seeing the answer

The sign and size of an NRI are as much a property of the cut-points as of the models. The set at 0.000 does not show the models are equivalent; it shows nobody moved at all - both cut-points sit below this cohort's risk distribution, both models put every patient into the top band, and that set asked nothing. A set of cut-points carried over from another disease without ever being checked against the local data looks exactly like this. 0.209 is the largest of the four, and reporting the largest is precisely the practice this page is criticising. And -0.045 is the set that flips the sign; it carries a chosen-after-seeing-the-answer flag in the statistical output, and it is left on the page so the reader can see how far that kind of choosing can go.

Under the 15% and 30% cut-points, model A moves 30 patients who did have an event (285 in that group) and 38 who did not (121 in that group) down one band, and the NRI is reported as 0.209. Why does that number read like a substantial improvement?

Show the answer and why

Correct answer: The non-event term is 0.314, and its denominator is under half the event group's, so each such patient carries more than twice the weight

The NRI adds two proportions with different denominators. The event group holds 285 patients and the non-event group only 121, more than a two-to-one ratio, so the non-event term of 0.314 is 38 over a small denominator while the event term of -0.105 is 30 over a large one. Converted back to heads, this set of cut-points takes 30 patients who did have an event and lowers their risk, in exchange for lowering the risk of 38 who did not - and it is reported as 0.209. So far fewer harmed than helped is reading a proportion as a head count. Both positive so it is robust does not hold either: 0.169 and 0.209 being positive guarantees nothing about a third set, and this page has one that is negative. How many false alarms you will trade for one missed case is a clinical trade to be stated out loud - a threshold probability forces you to state it, and the NRI does not.

The IDI is 0.0400 with a bootstrap 95% interval of 0.0139 to 0.0563, which does not cross zero. Does that establish that model A is better than model B?

Show the answer and why

Correct answer: Only that A separates the two groups more than B does. A's mean prediction in the non-event group moves -0.1044, the event group moves the same way, and the IDI looks only at the difference

The IDI does not depend on cut-points, but it is still a difference of two means, so a shift of the whole scale passes straight through it. Model A gives a lower mean risk in both groups - the non-event group moves -0.1044 and the event group moves the same way - and the IDI reads only the difference between those two shifts, indifferent to both absolute levels having drifted off the real risk. So an interval clear of zero supports one sentence only: A separates events from non-events more than B does. 0.4859 is A's mean prediction in the event group, and it is lower than B's rather than higher, which is what under-prediction looks like. 0.1213 is A's discrimination slope; a discrimination slope measures separation, calibration is a different thing, and model A on this page is the textbook case of a positive IDI with poor calibration.

The last row of the Brier curve is at six years, and its scores look respectable. Why should it not be read?

Show the answer and why

Correct answer: G(t) at six years is down to 0.125, so every survivor's weight is blown up around eightfold and the estimate is decided by very few people

The IPCW weight is 1 over G(t), and the smaller G(t) is the harder it magnifies. At six years G(t) is down to 0.125 with only a few dozen left in the risk set, every remaining person is weighted around eightfold, and the wobble is far larger than it looks. At five years 0.359 still holds up, and the rule of thumb is to stop reading once it falls below 0.2 - 0.125 is already past that line, so saying six years has not yet reached it has it exactly backwards. 0.222 is model A's Brier in that row; it being below the five-year value is not the model becoming accurate, it is a small heavily weighted remnant of the cohort, and a score carried by thirty-odd people has lost the basis for any comparison.

The NRI under one set of cut-points is 0.209, while the net-benefit difference between the same two models changes sign 10 times across the threshold grid. How should the conclusion be written?

Show the answer and why

Correct answer: The bootstrap interval for that cell runs from -67.1 up into positive values, crossing zero - so what to write is that no net-benefit difference was detected

Almost every row of these differences has an interval crossing zero, and the fifty per cent cell running from -67.1 to 25.6 is one of them, so the sentence to write is that at most thresholds no net-benefit difference was detected, and the direction of the difference itself keeps changing with the threshold. Picking the most extreme cell is the same disease in another form: -23.5 is the most negative of the seven cut-points reported, and reporting it is methodologically no different from the NRI picking its prettiest set of cut-points - and the full threshold grid runs further down still, so even being the most extreme is something that was selected. Nor does a positive upper bound make the models equally good - an interval crossing zero means these data cannot tell them apart, and claiming equivalence needs a non-inferiority design and a margin set in advance.

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.