The Daily Goal Horn
Advertisement

How our expected goals model works

NHL · model xg-nhl-v2-20261110-976284ae

What xG is

Expected goals (xG) is the chance that a shot attempt becomes a goal, judged from where and how it was taken. A shot with an xG of 0.12 goes in about 12 times out of 100 from that spot in that situation. Add up a team’s xG over a game and you get the number of goals its chances were worth, whoever was in net.

Trained on2023-24 to 2025-26361,725 shots
Held-out log loss0.21762025-26, lower is better
vs MoneyPuck−0.0037ours minus theirs, same shots; below 0 = ours better
xG vs goals+4.5%8,952 xG, 8,566 goals

Every number on this page and on the calibration page comes from the training job’s own output for this model.

Which shots it scores

Every unblocked attempt with a recorded location: shots on goal, shots that missed the net, and goals. Left out:

  • Blocked shots. The league logs where the block happened, not where the shot was taken from.
  • Shootout attempts, which are not part of the game’s goal count.
  • Penalty shots, which we pick out from the league’s on-ice count (one skater against none, outside a shootout).

Every NHL game since 2010-11 is scored. Live games are scored as the play-by-play arrives, and again when the league corrects an event.

What it looks at

39 inputs, all from the NHL’s public play-by-play feed. The percentage is how much of the model’s total improvement each group accounts for (LightGBM split gain), so it shows what the model leans on, not cause and effect.

  • Shot location46%

    Distance from the net and the angle to it.

  • What happened just before24%

    The previous play: what it was, which team made it, where, and how long before the shot; how fast the puck moved between the two spots and how far the shooting angle swung; rebounds (a shot on goal by the same team within 3 seconds), quick shots after a miss or a block, and rush chances.

  • Empty nets and manpower21%

    Whether either net is empty, and how many skaters each side has on the ice.

  • Shot type6%

    Wrist, snap, slap, backhand, tip-in, deflection, wraparound or other, as the league logs it.

  • Game situation3%

    Period, time elapsed, the shooting team’s goal differential and whether it is the home team.

The feed does not record passes before the shot, screens, or where the goalie was, so the model cannot see them. Two shots from the same spot after the same kind of play get the same xG.

How it was trained

LightGBM 4.7.0 gradient-boosted trees: 143 trees of up to 31 leaves each, learning rate 0.05, at least 200 shots in any leaf.

It learns from the 3 most recent completed seasons, weighted towards the newest: the newest season counts in full, the one before it about 18% as much, and the one before that about 3%. The league has changed how it logs some events over the years (quick rebounds in particular are logged far more often in recent seasons than a decade ago), so older seasons describe a different feed.

How those settings were chosen

We tried 36 combinations of training window, recency weighting and tree regularisation. Each was trained only on the seasons before each of 2022-23, 2023-24 and 2024-25 in turn and scored on that season. The chosen settings had the lowest log loss among those clearly better than an unweighted model trained on every season: 0.0074 lower per shot (chosen minus unweighted −0.0074, 95% interval −0.0077 to −0.0070, resampling 4,198 games).

How it was tested

Season 2025-26 was held out of everything above. A model with these settings trained on 2022-23 to 2024-25 then scored all 119,319 2025-26 shots: log loss 0.2176 (a model that knew only the league scoring rate gets 0.2582), AUC 0.787. We also scored the same shots with MoneyPuck’s public model; see the calibration page.

The live model, xg-nhl-v2-20261110-976284ae, has the same settings retrained on 2023-24 to 2025-26, so it has no held-out season of its own. The held-out results are evidence for the recipe, not for this exact set of trees.

Versions

Each stored xG value carries the version of the model that produced it. When a new model replaces this one, every game back to 2010-11 is scored again with it, and this page and the calibration page change in the same release. Older seasons are scored with today’s model, so their xG reflects how today’s game converts chances, not how that season’s did.

Model file sha256 aff564e013097d5802c39654e220e144cc39a2874456d1b8eb69944a769251d3

Where it is weak

  • It expects slightly too many goals: 8,952 xG against 8,566 goals (+4.5%) in 2025-26. Most of it is at even strength (+240 of +386 goals); relative to goals scored the gap is widest on the power play (+7.8%). We are tracking this season’s totals before deciding on a correction.
  • It ranks power play shots less well than others (AUC 0.69), likely because the feed has no passing data and power-play chances are built on passes.
  • For older games where the feed does not say which end each team defended, we work it out from the period’s shots once the period is over. Those seasons’ locations are less certain.
  • Rush chances are approximated: a shot soon after a play outside the attacking zone.