Introduction
Throughout this series we have progressively developed an NFL Elo model that estimates the underlying strength of every team. After each game, the ratings are updated as new evidence becomes available, producing an estimate of team strength before the next round of fixtures.
That naturally raises the next modelling question:
"How should we interpret the difference between two Elo ratings?"
A team's Elo rating has very little meaning in isolation. Knowing that one team is rated 1640 and another is rated 1540 tells us which team the model considers stronger, but it does not explain what that difference means in practical terms or how it relates to real NFL outcomes.
The real value of an Elo system lies in the difference between two ratings. That difference captures the model's estimate of the relative strengths of the teams and forms the foundation for every prediction the system makes.
Before introducing probability formulas, it is useful to ask a simpler question: when one team has a higher Elo rating than another, what has actually happened historically in similar situations?
In this article we answer that question by comparing pre-match Elo rating differences with historical NFL results, building an intuitive understanding of how rating gaps relate to winning before converting those differences into probabilities later in the series.
Why Elo Ratings Are Relative
One of the most common misconceptions about Elo ratings is that the absolute number is important.
In reality, Elo is a relative rating system. A rating of 1600 is neither good nor bad on its own. Its meaning depends entirely on the rating of the opposing team.
This is why Elo models focus on rating differences rather than individual ratings. The gap between two teams represents the model's estimate of their relative strengths and contains the information used to make predictions.
This idea appears throughout predictive modelling. In many systems it is the relationship between observations, rather than the individual values themselves, that carries the most useful information.
"An Elo rating is just a number. The difference between two Elo ratings is where the predictive information lives."
Using Historical Results to Interpret Elo
Before introducing a probability model, it is important to understand what the Elo ratings are already telling us.
If differences in Elo ratings genuinely reflect differences in team strength, we should observe a clear relationship between the size of the rating gap before a game and the eventual match outcome.
Rather than assuming that relationship exists, we can test it directly using the historical NFL games processed by our Elo model.
By grouping games with similar pre-match Elo differences and measuring how often the higher-rated team won, we can build an empirical interpretation of what different rating gaps represent in practice.
"A useful rating system should produce differences that correspond to predictable changes in real-world outcomes."
Preparing the Data
We begin by loading the game-level Elo dataset produced in the previous article. Each row contains the pre-match Elo ratings for both teams together with the final game result.
For this analysis we focus on non-neutral games and construct two additional variables:
- Pre-match Elo difference — the home team's Elo rating minus the away team's Elo rating before kick-off.
- Home win indicator — a binary variable indicating whether the home team won the game.
These variables allow us to compare rating differences with actual NFL outcomes across thousands of historical games, helping us understand how rating gaps translate into observed results before introducing a probability equation.
The complete Python implementation is shown below.
import polars as pl
# ------------------------------------------------------------------
# Configuration
# ------------------------------------------------------------------
ELO_PATH = "nfl_elo_game_level_home_mov_season.pq"
# ------------------------------------------------------------------
# Load the game-level Elo dataset
# ------------------------------------------------------------------
df = pl.read_parquet(ELO_PATH)
# ------------------------------------------------------------------
# Restrict the analysis to non-neutral games
# ------------------------------------------------------------------
df = df.filter(~pl.col("neutral"))
# ------------------------------------------------------------------
# Process games in chronological order
# ------------------------------------------------------------------
df = df.sort(["date_timestamp", "match_id"])
# ------------------------------------------------------------------
# Calculate the pre-match Elo difference and match outcome
# ------------------------------------------------------------------
df = df.with_columns(
# Difference in Elo ratings before the game
(pl.col("home_elo_pre") - pl.col("away_elo_pre"))
.alias("elo_diff_pre"),
# Binary indicator showing whether the home team won
(pl.col("home_score") > pl.col("away_score"))
.cast(pl.Int8)
.alias("home_win")
)
# ------------------------------------------------------------------
# Display a small sample of the prepared dataset
# ------------------------------------------------------------------
print(
df.select([
"home_team",
"away_team",
"home_elo_pre",
"away_elo_pre",
"elo_diff_pre",
"home_win"
]).head(5)
)
Estimating the Relationship from Historical Data
A single NFL game tells us very little about the relationship between Elo ratings and winning. Even if one team is substantially stronger than another, the weaker team will sometimes win because individual games are influenced by many unpredictable factors.
To understand how Elo differences relate to match outcomes, we therefore analyse thousands of historical games rather than focusing on individual results.
By combining games with similar pre-match Elo differences, we can reduce the effect of random variation and reveal the underlying relationship between rating gaps and winning frequency.
"Individual games are noisy. Reliable patterns emerge only when many observations are analysed together."
Calculating Empirical Win Rates
We group games into 25-point Elo intervals and calculate two simple statistics for each group:
- Games — the number of historical matches within that Elo range.
- Home win percentage — the proportion of those games won by the home team.
These empirical win rates provide an assumption-free view of how winning frequency changes as Elo differences increase. Rather than imposing a mathematical model, we first allow the historical data to show us the underlying relationship.
The complete Python implementation is shown below.
import polars as pl
# ------------------------------------------------------------------
# Configuration
# ------------------------------------------------------------------
ELO_PATH = "nfl_elo_game_level_home_mov_season.pq"
BIN_SIZE = 25
MIN_ELO_DIFF = -300
MAX_ELO_DIFF = 300
# ------------------------------------------------------------------
# Load the game-level Elo dataset
# ------------------------------------------------------------------
df = pl.read_parquet(ELO_PATH)
# ------------------------------------------------------------------
# Restrict the analysis to non-neutral games
# ------------------------------------------------------------------
df = df.filter(~pl.col("neutral"))
# ------------------------------------------------------------------
# Calculate the pre-match Elo difference and match outcome
# ------------------------------------------------------------------
df = df.with_columns(
# Difference between the home and away Elo ratings
(pl.col("home_elo_pre") - pl.col("away_elo_pre"))
.alias("elo_diff_pre"),
# Binary indicator showing whether the home team won
(pl.col("home_score") > pl.col("away_score"))
.cast(pl.Int8)
.alias("home_win")
)
# ------------------------------------------------------------------
# Restrict extreme Elo differences
# ------------------------------------------------------------------
# Large rating differences are uncommon and can produce unstable
# estimates because relatively few historical games exist.
# Clipping the values keeps the analysis focused on the range where
# sufficient data is available.
df = df.with_columns(
pl.col("elo_diff_pre")
.clip(MIN_ELO_DIFF, MAX_ELO_DIFF)
.alias("elo_diff_clipped")
)
# ------------------------------------------------------------------
# Group games into 25-point Elo intervals
# ------------------------------------------------------------------
# Each game is assigned to an Elo difference bin so that games with
# similar pre-match rating differences can be analysed together.
df = df.with_columns(
(
(pl.col("elo_diff_clipped") / BIN_SIZE)
.floor()
* BIN_SIZE
).alias("elo_diff_bin")
)
# ------------------------------------------------------------------
# Calculate empirical win rates for each Elo interval
# ------------------------------------------------------------------
win_rates = (
df.group_by("elo_diff_bin")
.agg([
pl.len().alias("games"),
pl.mean("home_win").alias("home_win_pct"),
])
.sort("elo_diff_bin")
)
# ------------------------------------------------------------------
# Display the calculated win-rate table
# ------------------------------------------------------------------
print(win_rates.head(10))
print(win_rates.tail(10))
Comparing Different Elo Models
Throughout this series we have progressively refined the original Elo model by introducing home advantage, margin of victory and seasonal carryover. Each extension was designed to produce a more realistic estimate of team strength while preserving the simplicity of the underlying rating system.
That naturally raises another important modelling question:
"Should improving a model change the meaning of its outputs?"
In a well-designed rating system, the answer should generally be no. The purpose of these enhancements is to improve the quality of the ratings, not to redefine what a given Elo difference represents.
If a 100-point Elo advantage reflects a particular level of expected performance, that interpretation should remain broadly consistent regardless of whether the model also accounts for home advantage, margin of victory or seasonal carryover.
We can test this by repeating the same empirical analysis for each Elo variant and comparing the resulting relationships between rating differences and historical match outcomes.
"Good model improvements increase accuracy without sacrificing interpretability."
Plotting the Relationship
For each Elo model, we calculate empirical home win percentages across identical 25-point Elo intervals and display the resulting curves on a single chart.
If our extensions have behaved as intended, the curves should remain remarkably similar. The improvements should produce better team ratings, while preserving the interpretation of the Elo rating scale itself.
The complete Python implementation is shown below.
import polars as pl
import matplotlib.pyplot as plt
# ------------------------------------------------------------------
# Configuration
# ------------------------------------------------------------------
ELO_FILES = [
("Clean Elo", "nfl_elo_game_level.pq"),
("Home Advantage", "nfl_elo_game_level_home.pq"),
("Home + MOV", "nfl_elo_game_level_home_mov.pq"),
("Home + MOV + Season", "nfl_elo_game_level_home_mov_season.pq"),
]
BIN_SIZE = 25
MIN_ELO_DIFF = -300
MAX_ELO_DIFF = 300
# ------------------------------------------------------------------
# Create the comparison chart
# ------------------------------------------------------------------
plt.figure(figsize=(10, 6))
# ------------------------------------------------------------------
# Process each Elo model independently
# ------------------------------------------------------------------
for label, path in ELO_FILES:
# Load the game-level Elo dataset
df = pl.read_parquet(path)
# Restrict the analysis to non-neutral games
df = df.filter(~pl.col("neutral"))
# Calculate the pre-match Elo difference and match outcome
df = df.with_columns(
(pl.col("home_elo_pre") - pl.col("away_elo_pre"))
.alias("elo_diff_pre"),
(pl.col("home_score") > pl.col("away_score"))
.cast(pl.Int8)
.alias("home_win")
)
# Restrict extreme Elo differences
df = df.with_columns(
pl.col("elo_diff_pre")
.clip(MIN_ELO_DIFF, MAX_ELO_DIFF)
.alias("elo_diff_clipped")
)
# Group games into 25-point Elo intervals
df = df.with_columns(
(
(pl.col("elo_diff_clipped") / BIN_SIZE)
.floor()
* BIN_SIZE
).alias("elo_diff_bin")
)
# Calculate the empirical home win rate for each interval
rates = (
df.group_by("elo_diff_bin")
.agg(
pl.mean("home_win").alias("home_win_pct")
)
.sort("elo_diff_bin")
)
# Plot the empirical win-rate curve
plt.plot(
rates["elo_diff_bin"],
rates["home_win_pct"],
label=label
)
# ------------------------------------------------------------------
# Format the comparison chart
# ------------------------------------------------------------------
plt.xlabel("Pre-match Elo difference (Home − Away)")
plt.ylabel("Home win percentage")
plt.title("Elo Rating Difference vs Historical Home Win Percentage")
plt.legend()
plt.grid(alpha=0.30)
plt.tight_layout()
# ------------------------------------------------------------------
# Display the completed chart
# ------------------------------------------------------------------
plt.show()
Interpreting the Results
The chart reveals a smooth, monotonic relationship between pre-match Elo difference and historical home win percentage across all four Elo models.
As the home team's Elo advantage increases, the proportion of games won by the home team also increases. Conversely, as the away team's rating advantage grows, the historical home win percentage steadily decreases.
Most importantly, the four curves remain remarkably similar. Despite introducing home advantage, margin of victory and seasonal carryover, the relationship between Elo differences and historical outcomes changes very little.
"Improving a rating system should refine the ratings, not redefine the rating scale."
This is exactly the behaviour we hoped to observe. Each enhancement introduced throughout the series improves how team strength is estimated, while preserving the interpretation of an Elo rating difference.
In practical terms, a given rating gap continues to represent broadly the same level of expected performance regardless of which Elo variant produced it.
Why This Matters
A rating system is only useful if its outputs remain interpretable.
If every refinement changed the meaning of a 50-point, 100-point or 200-point Elo advantage, comparing ratings across model versions would become difficult and explaining predictions would become far less intuitive.
Instead, our results show that the additional modelling assumptions improve the quality of the team ratings while preserving the meaning of the Elo scale itself.
That provides a solid foundation for the next stage of the series, where we move beyond interpreting Elo differences and begin converting them into estimated win probabilities.
What Have We Learned?
Throughout this article we have focused on interpreting, rather than extending, the Elo rating system. Before introducing probability equations, we first asked whether Elo rating differences correspond to meaningful differences in historical NFL outcomes.
"Do Elo rating differences correspond to real differences in historical NFL outcomes?"
The historical data provides a clear answer. As Elo rating differences increase, winning percentages change in a smooth and predictable way, demonstrating that the rating scale captures genuine information about relative team strength.
Just as importantly, this relationship remains remarkably consistent across every Elo model developed throughout the series. Home advantage, margin of victory and seasonal carryover improve how team strength is estimated without changing what an Elo rating difference fundamentally represents.
Key Takeaways
- Elo is fundamentally a relative rating system.
- Rating differences carry the predictive information, not the individual ratings themselves.
- Historical NFL results show a clear relationship between Elo differences and winning frequency.
- The modelling improvements introduced throughout the series preserve the interpretation of the Elo rating scale.
- A useful predictive model produces outputs that correspond to observable real-world behaviour.
Next Steps
We now understand what different Elo rating differences mean in practice. The next step is to convert those rating differences into estimated pre-game win probabilities using the standard Elo probability equation.
That naturally raises our next modelling question:
"How can an Elo rating difference be converted into a pre-game win probability?"
In the next article, Turning Elo Rating Differences into Win Probabilities we derive the Elo probability equation, explain why it produces its characteristic S-shaped curve, and show how rating differences can be transformed into practical pre-game win probabilities.