A National Hockey League (NHL) playoff team changes goalies. The next game looks cleaner. The broadcast booth reaches for the simple sentence: the goalie change saved the series.
That might be true. But a goalie switch is rarely random. Coaches make it after score pressure, defensive breakdowns, rebound trouble, or a run of dangerous chances.
A goalie change can reduce goals against, but the observed before-and-after comparison may mostly be measuring the defensive situation that forced the change.
Share: A goalie switch can look causal when the real change is happening in front of the net. #Causality #NHL #SportsAnalytics
In this article, we audit the headline by separating a goaltender intervention from shot quality.
The headline hides a selection problem
The NHL playoff schedule is active during the week of May 4, 2026 [1]. In a tight series, a coach may change the goalie after a bad game. The mistake is to compare goals against before and after the change without asking why the change happened.
The directed acyclic graph (DAG), a graph whose arrows do not loop back on themselves, treats GoalieChange as the treatment and GoalsAgainst as the outcome:
ScorePressure: series and game pressure that makes a change more likelyDefensiveBreakdowns: coverage mistakes that create dangerous chancesShotQualityAgainst: how dangerous the conceded shots areReboundControl: whether the goalie turns first shots into second chancesGoalsAgainst: the outcome people use to judge the move

Here is the same graph as a py-scm setup. This uses the py-scm reference implementation for a continuous Gaussian structural causal model (SCM). An SCM defines each variable through its direct causes. The coefficients are illustrative.
import numpy as np
from pyscm.reasoning import create_reasoning_model
nodes = [
"ScorePressure",
"DefensiveBreakdowns",
"GoalieChange",
"ShotQualityAgainst",
"ReboundControl",
"GoalsAgainst",
]
weighted_edges = [
("ScorePressure", "GoalieChange", 0.60),
("ScorePressure", "DefensiveBreakdowns", 0.40),
("ScorePressure", "GoalsAgainst", 0.20),
("DefensiveBreakdowns", "GoalieChange", 0.50),
("DefensiveBreakdowns", "ShotQualityAgainst", 0.90),
("DefensiveBreakdowns", "GoalsAgainst", 0.40),
("GoalieChange", "ReboundControl", 0.35),
("GoalieChange", "GoalsAgainst", -0.25),
("ReboundControl", "GoalsAgainst", -0.45),
("ShotQualityAgainst", "GoalsAgainst", 0.90),
]
idx = {node: i for i, node in enumerate(nodes)}
B = np.zeros((len(nodes), len(nodes)))
for parent, child, weight in weighted_edges:
B[idx[child], idx[parent]] = weight
A = np.eye(len(nodes)) - B
cov = np.linalg.inv(A) @ np.eye(len(nodes)) @ np.linalg.inv(A).T
model = create_reasoning_model(
{"nodes": nodes, "edges": [(p, c) for p, c, _ in weighted_edges]},
{"v": nodes, "m": [0.0] * len(nodes), "S": cov.tolist()},
)
The key idea is that DefensiveBreakdowns points into both GoalieChange and ShotQualityAgainst. NHL tracking and analytics often distinguish shot volume from shot danger, including high-danger areas and expected-goals-style reasoning [2, 3].
The query asks what changed
The inference code compares observing a goalie change with setting a goalie change:
raw_slice = model.pquery({"GoalieChange": 1.0})[0]["GoalsAgainst"]
do_change = model.iquery("GoalsAgainst", {"GoalieChange": 1.0})
do_no_change = model.iquery("GoalsAgainst", {"GoalieChange": 0.0})
change_effect = model.equery(
"GoalsAgainst",
{"GoalieChange": 1.0},
{"GoalieChange": 0.0},
)
raw_slice asks what goals against look like when a goalie change is observed. change_effect asks what changes when the goalie switch is forced while the rest of the graph follows from that intervention.
Observed goalie-change gap: +0.20
Intervention effect: -0.41
Observed minus effect: +0.61
The observed slice is worse because goalie changes are selected by trouble. The intervention is beneficial in this toy model because it improves rebound control and directly reduces goals against.

What the model can support
The model supports a narrow statement: a goalie change can help and still look bad in the raw comparison. That is not a contradiction. It means the switch happened in a bad state.
The better evidence would compare shot quality before and after the switch, not just goals. If goals fall because high-danger chances fall, the defense deserves more credit. If high-danger chances stay constant and goals fall, the goalie-change story gets stronger.
Sources
- Schedule for May 4, 2026, NHL, accessed April 28, 2026.
- NHL EDGE Puck and Player Tracking Statistics Glossary, NHL, accessed April 28, 2026.
- Analytics with Alison: Expected Goals, Seattle Kraken, accessed April 28, 2026.
Download the runnable standalone Python example: Python example ZIP.

Leave a Reply