Our player projections might say a guard will get 0.7 steals tonight. Nobody gets 0.7 steals. He'll finish with zero, one, two, maybe three. For a stat like points, a single projected number is a fair summary. For steals and blocks, it hides the question most people actually care about: how likely is he to get at least one?
So for these stats, we treat the projection as a rate and turn it into chances. This post shows how well that works, where it slips, and a fix we tried that made things worse.
From one number to a set of chances
Steals and blocks are counted events: rare, discrete, and each one more or less a separate piece of luck. The classic model for counts like that is the Poisson distribution. Give it an expected rate and it tells you how often you should see 0, 1, 2 and so on. A player expected for 0.75 steals should come away empty about 48% of the time, with exactly one about 35%, and with two or more about 18%.
That's the "model-implied" number on the player deep-dive. To check that it's honest, we went back to three seasons of predictions, 62,156 player-games, grouped them by expected rate, and compared the predicted shares with what happened.
Figure 1. One expected rate, three outcomes: predicted vs actual share of games
Predicted by the rateActually happened
Steals: players expected for 0.5–1.0 (38,780 player-games)
Blocks: players expected for 0–0.5 (38,137 player-games)
Source: HoopModel player-projection validation before launch: 62,156 player-games over three test seasons (2023-24, 2024-25, 2025-26), pooled. Bins with fewer than 200 player-games are left out.
Show the data
| Stat and band | Outcome | Predicted | Actual |
|---|---|---|---|
| Steals 0.5–1.0 | 0 | 47.5% | 48.5% |
| Steals 0.5–1.0 | 1 | 34.9% | 32.9% |
| Steals 0.5–1.0 | 2 or more | 17.6% | 18.6% |
| Blocks 0–0.5 | 0 | 74.9% | 75.5% |
| Blocks 0–0.5 | 1 | 21.2% | 19.8% |
| Blocks 0–0.5 | 2 or more | 3.9% | 4.7% |
For typical players, it works. Within about two points, the rate gets the whole shape of the outcome right, not just the average.
Where it slips: busy defenders have more quiet nights
Further out, a consistent pattern appears. The higher a player's expected rate, the more his real games include nights with none, beyond what the Poisson curve predicts. For players expected to block two to three shots, zero-block games happened 15.2% of the time against 10.3% predicted, and the model over-forecast games with two or more (66.6% predicted, 63.2% actual).
Figure 2. Where the rate slips: actual minus predicted share of games, by expected rate
Games with noneGames with 2 or more
Steals (percentage points)
Blocks (percentage points)
Source: HoopModel player-projection validation before launch: 62,156 player-games over three test seasons (2023-24, 2024-25, 2025-26), pooled. Bins with fewer than 200 player-games are left out.
Show the data
| Stat | Expected per game | Player-games | None: predicted | None: actual | 2+: predicted | 2+: actual | None gap by season |
|---|---|---|---|---|---|---|---|
| Steals | 0–0.5 | 6,015 | 66.4% | 67% | 6.5% | 7.5% | -1.1 to 3.7 pts |
| Steals | 0.5–1.0 | 38,780 | 47.5% | 48.5% | 17.6% | 18.6% | -0.2 to 3 pts |
| Steals | 1.0–1.5 | 15,066 | 30.8% | 32.6% | 33.2% | 33.2% | -0.1 to 3.3 pts |
| Steals | 1.5–2.0 | 2,176 | 19.3% | 21.6% | 49.1% | 46.2% | 1.9 to 2.4 pts |
| Blocks | 0–0.5 | 38,137 | 74.9% | 75.5% | 3.9% | 4.7% | -1.9 to 2.3 pts |
| Blocks | 0.5–1.0 | 17,450 | 50.8% | 52.4% | 15.3% | 16% | -0.3 to 3 pts |
| Blocks | 1.0–1.5 | 4,301 | 30.4% | 33.8% | 33.7% | 32.9% | 1.3 to 4.4 pts |
| Blocks | 1.5–2.0 | 1,553 | 18.3% | 22.6% | 50.9% | 49.4% | -0.4 to 6.8 pts |
| Blocks | 2.0–3.0 | 643 | 10.3% | 15.2% | 66.6% | 63.2% | 2.4 to 10.6 pts |
The average is still right. Those players' actual blocks per game match the expected rate closely. What's off is the spread. Poisson assumes a steady rate over the minutes played, and an elite shot-blocker's nights aren't steady. Our reading is that foul trouble, blowouts that cut minutes, and opponents who simply stop attacking the rim all produce more empty nights than a fixed rate would.
The fix that made it worse
We tried correcting the tails directly: a flexible mapping, learned from a held-back slice of each training season, from the expected rate to the real chance of a zero night or a 2+ night. It made things worse. For steals, the miss on the share of 2+ games roughly doubled, from 2.3 to 4.3 points. For blocks it didn't improve on average, and swung widely from run to run.
Figure 3. A flexible correction for the tails: average miss on the share of 2+ games
Source: HoopModel experiment: correction fitted on a held-back slice of each training season, scored on the test season.
Show the data
| Method | Stat | Avg miss (pts) | Best run | Worst run |
|---|---|---|---|---|
| Plain rate | Steals | 2.3 | 0.2 | 3.9 |
| Flexible fix | Steals | 4.3 | 2.3 | 6.4 |
| Plain rate | Blocks | 3.6 | 2.6 | 5.0 |
| Flexible fix | Blocks | 3.6 | 0.6 | 8.2 |
The defect is real, but the region it lives in is thin: only a few hundred player-games a season have an expected rate above two. A flexible correction learned from so few games mostly learned their noise. The better fix is probably a distribution built to allow extra spread, rather than a patch on top of Poisson. Until we've tested one, the plain rate stays: a known, small, one-directional bias is easier to live with than a correction that moves unpredictably.
How to read steals and blocks on our site
- For most players, the model-implied chances on the deep-dive can be taken at face value.
- For the league's busiest shot-blockers, shade the chance of a big night down a few points and the chance of a quiet night up.
- Don't read too much into a single night either way: even a perfectly calibrated 70% chance of a block means three games in ten without one.