How it works
Every advanced number on our hockey pages comes from two models we built ourselves from the NHL's public game data: expected goals (how likely each shot was to go in) and lineup-adjusted impact (RAPM: how much a skater changes his team's chances, after accounting for everyone he plays with and against). Both were graded on a season they had never seen.
How likely was that shot to go in?
For every unblocked shot (goals, saves and misses) since 2024-25, we know where it was taken from, what kind of shot it was, and what happened just before. A logistic regression turns that into a probability of scoring:
- Distance and angle to the net, with bends at 10, 20, 35 and 55 feet and at 30 and 60 degrees (so in-close shots aren't treated like a straight line).
- Shot type: wrist, snap, slap, backhand, tip-in, deflection, wrap-around.
- Rebound: his team shot within the previous 3 seconds (and how much the angle changes the rebound's value).
- Rush: the previous event, within 4 seconds, happened in the neutral or defensive zone.
- Strength: power play or shorthanded vs even strength.
Left out on purpose: blocked shots (the NHL records where the block happened, not where the shot came from), empty-net shots, penalty shots and shootouts. We don't use the shooter's identity, so a player's xG says how good his chances were, not how good he is.
Graded the honest way
We built the model on 2024-25 only, then asked it to price every 2025-26 shot it had never seen. Lower log loss is better; AUC is the chance it rates a random goal above a random non-goal.
| Model, built on 2024-25 | Log loss, 2025-26 | AUC | Expected goals | Actual goals |
|---|---|---|---|---|
| Spreadsheet Sports xG | 0.2246 | .745 | 7,927 | 7,572 |
| Distance only | 0.2324 | .692 | 7,669 | 7,572 |
| League-average rate | 0.2489 | .495 | 7,356 | 7,572 |
Calibration on 2025-26 (shots in ten equal groups, by predicted chance)
| Group | Predicted | Actual | Shots |
|---|---|---|---|
| 1 | 0.7% | 0.5% | 11,101 |
| 2 | 1.4% | 1.3% | 11,107 |
| 3 | 2.2% | 2.0% | 11,107 |
| 4 | 3.3% | 2.9% | 11,107 |
| 5 | 4.7% | 4.1% | 11,106 |
| 6 | 6.2% | 6.2% | 11,110 |
| 7 | 7.9% | 8.2% | 11,076 |
| 8 | 10.1% | 10.9% | 11,130 |
| 9 | 13.5% | 13.9% | 11,105 |
| 10 | 21.4% | 18.1% | 11,117 |
By strength, 2025-26
| Situation | Shots | xG | Goals |
|---|---|---|---|
| 5v5 | 87,452 | 5,553 | 5,362 |
| PP | 18,549 | 1,945 | 1,774 |
| SH | 2,471 | 196 | 174 |
| other EV | 2,594 | 232 | 262 |
Out of sample, the model priced 2025-26 about 5% high in total (tip-ins especially), because league scoring and scorekeeping drift a little each year. So the numbers on player pages use the same model refit on both seasons, with one small intercept shift per season so each completed season's expected goals add up to its actual goals (2026-27 so far uses 2025-26's shift). The ranking of shots is unchanged; only the level moves.
Who actually moves the needle at 5v5?
On-ice numbers ("his team had 55% of the expected goals with him on the ice") mix a player with his linemates, his opponents and his coach's deployment. So we use the NHL's shift charts to rebuild every 5-on-5 stretch with the same ten skaters on the ice (about 440,000 per season), add up the expected goals each side created in it, and estimate every skater at once with a ridge regression: one offense number and one defense number per player, plus home ice, the score (trailing teams push) and whether the shift started with an offensive- or defensive-zone faceoff.
team xG per 60 in a shift = baseline + Σ offense of its 5 skaters + Σ defense of the other 5 + home ice + score + zone start
What the pages show. One season of RAPM barely repeats (year-to-year r .439 for net impact), so the headline offense, defense and net impact numbers on player pages and leaderboards come from one fit on 2024-25 and 2025-26 together (1,756,680 team-shifts, one offense and one defense number per skater across both seasons, same penalty). That number is the same in both season views. Each RAPM row also shows the fit on that season alone, and the backtest below grades the single-season version, the honest test.
The ridge penalty pulls everyone toward average until the data says otherwise. We picked its strength by asking which setting, fit on 2024-25, best predicts 2025-26 shifts (best: λ = 100,000 seconds of shrinkage, roughly 1,667 minutes of average-player ice time).
| Predictor, built on 2024-25 | 2025-26 shift xG/60 | 2025-26 shift goals/60 |
|---|---|---|
| RAPM (ours, lineup-adjusted) | .038 | .014 |
| Relative to team (on − off) | .034 | .014 |
| Raw on-ice rates | .035 | .012 |
Weighted correlation with what happened in every 2025-26 shift (890,282 team-shifts). Single shifts are tiny samples, so every number is small; the comparison is what matters. Gaps, bootstrapped over games: RAPM − raw: +0.0027 (95% CI +0.0018 to +0.0039); RAPM − relative: +0.0037 (95% CI +0.0016 to +0.0055).
Which numbers are skill, which are luck?
The same player's 2024-25 value against his 2025-26 value (skaters with 500+ minutes in both seasons; goalies with 1,200+). A stat that's mostly skill repeats; a stat that's mostly luck doesn't. That's why finishing (goals minus expected goals) gets a small weight in Scoring while chance quality (ixG/60) gets a big one, and why on-ice defense numbers, which repeat less than offense, are best read over two seasons.
| Skater metric | r | n |
|---|---|---|
| Goals per 60 G/60 | .801 | 521 |
| Chance quality ixG/60 | .947 | 521 |
| Finishing G − xG | .300 | 521 |
| Shots per 60 SOG/60 | .896 | 521 |
| Primary assists per 60 A1/60 | .723 | 521 |
| 5v5 primary assists 5v5 A1/60 | .508 | 521 |
| Offensive impact Off. RAPM | .565 | 521 |
| Defensive impact Def. RAPM | .442 | 521 |
| Net impact RAPM net | .439 | 521 |
| Chances for vs team Rel xGF/60 | .643 | 521 |
| Chances against vs team Rel xGA/60 | .431 | 521 |
| Expected goal share xGF% | .506 | 521 |
| Goal share GF% | .303 | 521 |
| Hits per 60 Hits/60 | .916 | 521 |
| Blocked shots per 60 Blk/60 | .894 | 521 |
| Takeaways per 60 TK/60 | .409 | 521 |
| Goalie metric | r | n |
|---|---|---|
| Goals saved above expected GSAx | .182 | 50 |
| Save % vs expected dSV% | .110 | 50 |
| Save % SV% | .160 | 50 |
| High-danger save % HD SV% | .184 | 50 |
| Medium-danger save % MD SV% | .105 | 50 |
| Low-danger save % LD SV% | .138 | 50 |
What predicts next season?
| Target (2025-26) | From our xG number (2024-25) | From the plain stat (2024-25) | n |
|---|---|---|---|
| Next season's 5v5 goal share (GF%) | .298 | .303 | 521 |
| Next season's goals per 60 | .822 | .801 | 521 |
| Goalies: next season's save % | .081 | .160 | 50 |
RAPM rows here use each season's own fit (the pooled number is the same in both seasons by design). Rows below: on-ice xGF% vs GF%; ixG/60 vs goals/60; save % vs expected vs plain save %. The honest read: a player's chance quality predicts next year's goals better than his goals do. For on-ice goal share, expected goals and actual goals predict next season about equally well. And no goalie number, ours or the plain save %, repeats much from one season to the next (about 50 goalies, r of 0.1 to 0.2), so treat one goalie season as a description of that season, not a forecast.
Net impact, top 10 (two seasons pooled)
- 1Brandon HagelTBL+0.45
- 2Nathan MacKinnonCOL+0.42
- 3Brady TkachukOTT+0.40
- 4Jordan SpenceOTT+0.40
- 5Zach WerenskiCBJ+0.36
- 6Adam FoxNYR+0.35
- 7Moritz SeiderDET+0.35
- 8Robert ThomasSTL+0.34
- 9Leon DraisaitlEDM+0.32
- 10Connor McDavidEDM+0.32
Goals saved above expected
- 1Logan ThompsonWSH+35.6
- 2Ilya SorokinNYI+25.3
- 3Jeremy SwaymanBOS+25.2
- 4Scott WedgewoodCOL+22.4
- 5Andrei VasilevskiyTBL+21.3
- 6Igor ShesterkinNYR+17.8
- 7Jet GreavesCBJ+15.4
- 8Devin CooleyCGY+14.5
- 9John GibsonDET+13.8
- 10Jakub DobesMTL+13.6
What it can't see
- No passes, screens or pre-shot movement. The NHL's public play-by-play has shot locations but no passing data, so a cross-seam one-timer and a point shot from the same spot look more alike than they are. Public tracking data would fix that; we don't use it.
- Arena scorekeepers. Shot locations, hits, takeaways and giveaways are recorded by each rink's staff, and some rinks are more generous. We don't adjust for rink.
- RAPM is noisy. That's why the headline number pools two seasons. Linemates who almost always play together still split credit uncertainly, and the pooled fit doesn't see aging or role changes inside the window. Treat percentile gaps under about 10 points as ties.
- Shift data gaps. 57 games in 2024-25 have no public shift chart, so their 5v5 on-ice numbers and RAPM are missing (box scores and xG are complete).
- Goalies are graded on unblocked shots (xG includes misses), so goals saved above expected also rewards goalies whose teams force bad misses. Save % by danger uses shots on goal only.
Play-by-play, shift charts and season stats via the NHL's public game data (logged out). All models, metrics, percentiles and roles computed by Spreadsheet Sports. We don't republish any other site's ratings.