Simul RAPM & Clutch RAPM

How a possession-level plus-minus model is built, regularized, and made honest about its own uncertainty

The Idea

Raw plus-minus is misleading because a player's number is tangled up with the four teammates and five opponents on the floor with them. RAPM, regularized adjusted plus-minus helps unmuddy the waters. Every possession of the last four seasons becomes one row in a giant regression: the ten players on the floor are the inputs, the points scored on that possession is the output. Solve the regression and each player gets an offensive and defensive coefficient: their estimated point impact per possession, holding everyone else constant.

The Regression

Ridge regression and why it shrinks

With thousands of players sharing the floor in tangled combinations, an ordinary regression overfits wildly, a player with few possessions can land at +40 just because their handful of minutes happened to go well. Ridge regression adds a penalty on large coefficients, pulling every estimate toward zero. The less data backing a player, the harder they get pulled. The result is conservative and stable, the results have to be backed by volume.

raw estimateafter ridge0extreme values shrink toward zero — noisy estimates are pulled in hardest
Each line is a player: the raw fit on the left, the regularized estimate on the right.

Offense and defense get their own penalty strengths because defensive signal is noisier and needs heavier shrinkage. Home court is included as its own term so it doesn't bleed into player numbers.

Informative priors

A plain ridge model assumes every player is league-average until the possessions say otherwise. Instead of this we use the two-way role scores as priors, this way the regression only has to nudge players instead of finding out exaclty how good they are from scratch. This stabilizes players with limited minutes and speeds the model toward sensible answers.

poorelitebox-score z-score priorstart heredata nudges itInstead of assuming every player is league-average (0), the model starts each playerat a prior from their box-score profile, then lets possession data move them.
The prior sets the starting point, possession data moves the player from there.

Cleaning the Data

Garbage-time filter

Blowout minutes are mostly bench players going through the motions, and the points scored in them say nothing about real rotation impact. Fourth-quarter possessions in a decided game are dropped, with the margin cutoff tightening as the clock winds down, a 25-point lead with eight minutes left is still garbage, but late in the game it takes a smaller margin to qualify.

Fourth-quarter blowout possessions are dropped, the cutoff tightens as time runs out1525margin> 6:00 left±256:00–3:00±20< 3:00 left±15DROPPEDKEPT
Red zone is filtered out; green is kept. Possessions above each step's margin line are dropped.
Recency weighting

Four seasons of data give the model enough possessions to be stable, but basketball from three years ago is not counted the same as this season'. Every possession carries a season weight, climbing sharply toward the current season. The current year dominates heavily, older years are there to anchor players who haven't accumulated much recent volume.

Older possessions still count, but recent basketball is weighted far more heavily2022-232023-242024-252025-26
Season weights applied to every possession in the regression.

Honest Uncertainty

Bootstrapped confidence intervals

A single RAPM number hides how sure the model is. To measure that, the entire regression is refit fifty times, each on a dataset resampled with replacement from the original possessions. Players with lots of stable data barely move across refits; players on thin or noisy samples bounce around. The spread of those fifty estimates becomes a 95% confidence interval. The bracket shown next to every player on the leaderboard.

Refit the model on 50 resampled datasets — the spread of estimates is the uncertaintyestimate2.5%97.5%the shaded middle 95% is the confidence interval you see on every player
The distribution of resampled estimates; the shaded middle 95% is the reported interval.

This is why the player table can be sorted by the lower bound of the interval, not just the point estimate. The lower bound of the confidence interval is the models most confident & conservative guess.

Clutch RAPM

The clutch model is the same machinery run on a subset: possessions in the fourth quarter or later, with five minutes or less on the clock and the score within five. The problem is obvious, clutch possessions are somewhat rare, so the raw estimates are extremely noisy. A player with forty clutch possessions who happened to be on the floor for a few big shots would look like a superstar.

Clutch shrinkage
clutch RAPM = w × raw clutch + (1 − w) × regular RAPM,   where  w = poss / (poss + 100)

Each player's clutch estimate is blended with their regular RAPM (since logically we wouldn't expect insane gains / losses in skill because of the time period), weighted by how many clutch possessions they actually have. Below a hundred clutch possessions the number leans mostly on the player's overall RAPM; well above it, the clutch data takes over. This is why the leaderboard defaults to a clutch-possession minimum, in order to keep the data based on mostly the clutch performance.

Clutch weight = poss / (poss + 100). Small samples lean on regular RAPM; big ones trust the clutch data.1.00.50100 poss → half weightclutch possessions →weight on clutch
The shrinkage weight as a function of clutch possessions played.

Reading the Numbers

As with everything here, this is a model, not the truth. RAPM cannot see why a player is good, only that lineups featuring them tend to win the possession battle. It is one strong estimate among several worth triangulating.

See the RAPM leaderboard
Offensive, defensive, total, and clutch RAPM for every player — sortable, filterable, with confidence intervals.