Introduction
In the previous two articles we built and validated a baseline NFL Elo model. That implementation was deliberately simple, allowing us to understand exactly how the rating system behaves before introducing any additional modelling assumptions.
A good baseline model deliberately omits many real-world effects. Its purpose is not to be perfect, but to provide a simple, transparent foundation that can be validated before additional complexity is introduced.
The next question is therefore not "What feature should we add?", but rather:
"Is there clear evidence that the current model is missing an important real-world effect?"
Across many professional sports, historical results consistently show that teams playing at home tend to outperform visiting teams more often than would be expected if location had no influence. This phenomenon is commonly referred to as home advantage.
Whether that effect exists in our historical NFL dataset—and whether it is large enough to justify extending the baseline Elo model—is the question we answer in this article.
If the data supports introducing home advantage, we can then incorporate it into the Elo framework in a way that improves the model while preserving the meaning of the underlying ratings.
Why Add New Features One at a Time?
Every additional modelling assumption increases the complexity of a model. While that extra complexity may improve performance, it also makes the model more difficult to understand, validate and debug.
For that reason, experienced modellers rarely introduce several new assumptions at once. Instead, they make one carefully chosen change, evaluate its impact, and only then decide whether that improvement deserves a permanent place in the model.
"Only add a modelling assumption when there is evidence that it improves the representation of reality."
Throughout the SharpModels series we follow exactly that philosophy. Every article introduces a single modelling assumption, explains why it is being added, implements it with the smallest possible change to the code, and then evaluates its effect before moving on to the next enhancement.
In this article we begin by putting Elo to one side and asking a much simpler question:
"Do home teams actually win more often than away teams?"
If the answer is yes, we can then determine the most appropriate way to incorporate that information into the Elo model without changing what the ratings themselves represent.
Does Home Advantage Exist?
Before introducing any new modelling assumption, we should first ask whether the historical data provides evidence that the effect actually exists.
At this stage we deliberately ignore Elo ratings, team strength and every other part of the model. Those questions come later. Our objective here is much simpler:
"Do teams playing at home win more often than teams playing away?"
If the answer is no, there is little reason to make the model more complicated. If the answer is yes, we can then investigate the most appropriate way to represent that advantage within the Elo framework.
Separating observation from modelling is an important principle throughout this series. We first establish that an effect exists, and only then decide how it should be incorporated into the model.
Measuring Home Advantage
The code below performs a straightforward analysis of the historical NFL results dataset. It does not calculate Elo ratings or make predictions. Instead, it simply measures how often the home team wins under different playing conditions.
Three separate values are calculated:
- All games – every completed game in the historical dataset.
- Non-neutral games – games where one team has home advantage.
- Neutral-site games – games played at venues where neither team is designated as the home side.
This comparison acts as a simple validation check. If location genuinely influences performance, we would expect home teams to win more frequently in non-neutral games, while games played at neutral venues should move much closer to an even split between the two teams.
The implementation itself is intentionally simple. We clean the data, identify completed games, classify neutral-site fixtures, and then calculate the proportion of home victories within each group.
import polars as pl
# ------------------------------------------------------------------
# Load the historical NFL results dataset
# ------------------------------------------------------------------
DATA_PATH = "nfl_games_data.csv"
df = pl.read_csv(DATA_PATH)
# ------------------------------------------------------------------
# Standardise the neutral-site flag
# ------------------------------------------------------------------
df = df.with_columns(
pl.when(pl.col("neutral").is_null())
.then(False)
.otherwise(pl.col("neutral"))
.cast(pl.Boolean)
.alias("neutral")
)
# ------------------------------------------------------------------
# Keep only completed games
# ------------------------------------------------------------------
df = df.filter(
pl.col("home_score").is_not_null() &
pl.col("away_score").is_not_null()
)
# ------------------------------------------------------------------
# Determine whether the home team won each game
# ------------------------------------------------------------------
df = df.with_columns(
(pl.col("home_score") > pl.col("away_score")).alias("home_win")
)
# ------------------------------------------------------------------
# Calculate overall home win percentage
# ------------------------------------------------------------------
overall_home_win = df.select(
pl.col("home_win").mean()
).item()
# ------------------------------------------------------------------
# Calculate home win percentage for non-neutral games
# ------------------------------------------------------------------
home_win_non_neutral = (
df.filter(pl.col("neutral") == False)
.select(pl.col("home_win").mean())
.item()
)
# ------------------------------------------------------------------
# Calculate home win percentage for neutral-site games
# ------------------------------------------------------------------
home_win_neutral = (
df.filter(pl.col("neutral") == True)
.select(pl.col("home_win").mean())
.item()
)
# ------------------------------------------------------------------
# Display the results
# ------------------------------------------------------------------
print(
"Home win percentage (all games): {:.2f}%".format(
100 * overall_home_win
)
)
print(
"Home win percentage (non-neutral): {:.2f}%".format(
100 * home_win_non_neutral
)
)
print(
"Home win percentage (neutral sites): {:.2f}%".format(
100 * home_win_neutral
)
)
Interpreting the Results
Running the code produces three home win percentages:
- All games – approximately 57%.
- Non-neutral games – a very similar value.
- Neutral-site games – much closer to an even split between the two teams.
These results show a clear association between being the home team and winning more frequently in the historical NFL dataset. Home teams enjoy a measurable advantage in standard fixtures, while that advantage is greatly reduced when games are played at neutral venues.
Although this analysis does not explain why home teams perform better, it does provide strong evidence that match location is associated with game outcomes and is therefore a factor worth representing within the Elo model.
What These Results Do — And Do Not — Tell Us
This analysis establishes that home advantage is present in the historical data, but it does not identify the causes of that advantage.
Crowd support, travel, stadium familiarity, environmental conditions, scheduling and many other factors may all contribute. From the perspective of Elo, however, those individual causes are less important than the overall effect they produce.
The analysis also does not tell us how large the Elo adjustment should be. A home win percentage of approximately 57% cannot be converted directly into Elo points. The observed effect tells us that home advantage exists; determining how to represent that effect within the rating system is a separate modelling problem.
"Observation tells us that an effect exists. Modelling determines how best to represent that effect."
Choosing a Home Advantage Adjustment
For the educational examples in this series, we use a fixed home advantage adjustment of 65 Elo points.
The exact value is not the focus of this article. Its purpose is simply to demonstrate how a contextual adjustment can be incorporated into the Elo framework while keeping the implementation as clear as possible.
It should not be interpreted as a universally optimal value. The most appropriate adjustment depends on the sport, the historical dataset, the rating methodology and the objective being optimised.
In practice, parameters such as home advantage are typically estimated and validated using historical data. The values used in production rating systems will often differ from those used in educational examples and may evolve as additional seasons of data become available.
The important idea is not the precise value of the adjustment. The important idea is that the adjustment is supported by evidence and incorporated in a way that preserves the meaning of the underlying Elo ratings.
How Home Advantage Fits Into Elo
Having established that home advantage exists in the historical data, the next question is how that effect should be represented within the Elo model.
It might seem natural to permanently increase the rating of the home team before each game. However, doing so would fundamentally change what an Elo rating is intended to represent.
An Elo rating is designed to estimate a team's underlying strength. Playing at home does not permanently change that strength. Instead, it changes the circumstances under which a particular game is played.
"Home advantage influences expectations, not team quality."
For that reason, the underlying Elo ratings remain unchanged. Instead, we apply a temporary adjustment only when calculating the expected probability of the home team winning.
If the same two teams played again tomorrow with the venue reversed, the home advantage adjustment would simply be applied to the other team, while the underlying Elo ratings would remain exactly the same.
Try It Yourself: How Home Advantage Changes Elo Expectations
Adjust the ratings and home advantage value to see how a temporary Elo boost changes the expected win probabilities.
↓
Team A expected win probability: 63.4%
Team A is at home, so its rating is temporarily increased before calculating the expected probability. The underlying Elo rating is not permanently changed.
The Mathematical Change
In Article 1 we introduced the Elo expected score calculation. Rather than changing that equation, we simply adjust the home team's rating immediately before it is used.
R_home_adjusted = R_home + HOME_ADVANTAGE
This adjusted rating is then used only when calculating the expected probability for that particular game.
Once the expected probabilities have been calculated, the Elo update proceeds exactly as before. The stored ratings for both teams remain unchanged, and only the prediction has taken the temporary home advantage adjustment into account.
This distinction preserves the meaning of the Elo ratings throughout the model. They continue to represent long-term team strength, while home advantage remains a contextual factor that applies only to individual matches.
"An Elo rating should describe the team, not the circumstances of a single game."
Why This Design Works
Treating home advantage as a temporary adjustment provides several important benefits.
- The underlying Elo ratings remain directly comparable between every team.
- Neutral-site games naturally revert to the baseline Elo model without any additional logic.
- The modification is transparent, requiring only a small change to the original algorithm.
- The same framework can later be extended to incorporate other contextual factors if required.
The important idea is not the exact value of the home advantage adjustment. The important idea is that the adjustment is supported by evidence and incorporated in a way that preserves the meaning of the underlying Elo ratings.
With the modelling framework established, implementing the change in Python requires only a very small modification to the baseline Elo algorithm.
Implementing Home Advantage in Python
With the modelling framework established, implementing home advantage requires only a small modification to the baseline Elo algorithm.
The overall structure of the model remains the same. Games are still processed chronologically, expected probabilities are calculated before each game, and both teams' ratings are updated after the result.
The only difference is that we temporarily increase the home team's rating when calculating the expected outcome. Once that probability has been calculated, the algorithm continues exactly as before.
"Good models often improve through small, well-justified changes rather than complete redesigns."
The complete implementation is shown below. Compared with the baseline Elo model from Article 1, only a handful of lines have been modified.
import polars as pl
# ------------------------------------------------------------------
# Configuration
# ------------------------------------------------------------------
INPUT_FILE = "nfl_games_data.csv"
GAME_LEVEL_OUTPUT_CSV = "nfl_elo_game_level_home.csv"
GAME_LEVEL_OUTPUT_PARQUET = "nfl_elo_game_level_home.pq"
BASE_ELO = 1500.0
K = 20.0
HOME_ADVANTAGE = 65.0
# ------------------------------------------------------------------
# Expected win probability
# ------------------------------------------------------------------
def expected_score(r_a, r_b):
return 1.0 / (1.0 + 10 ** ((r_b - r_a) / 400.0))
# ------------------------------------------------------------------
# Load historical results
# ------------------------------------------------------------------
df = pl.read_csv(INPUT_FILE)
# ------------------------------------------------------------------
# Standardise the neutral-site flag
# ------------------------------------------------------------------
df = df.with_columns(
pl.when(pl.col("neutral").is_null())
.then(False)
.otherwise(pl.col("neutral"))
.cast(pl.Boolean)
.alias("neutral")
)
# ------------------------------------------------------------------
# Process games chronologically
# ------------------------------------------------------------------
df = df.sort(["date_timestamp", "match_id"])
elo = {}
rows = []
for row in df.iter_rows(named=True):
home = row["home_team"]
away = row["away_team"]
hs = row["home_score"]
aas = row["away_score"]
if hs is None or aas is None:
continue
r_home = elo.get(home, BASE_ELO)
r_away = elo.get(away, BASE_ELO)
# --------------------------------------------------------------
# Apply home advantage only when calculating expectation
# --------------------------------------------------------------
if row["neutral"]:
r_home_adj = r_home
else:
r_home_adj = r_home + HOME_ADVANTAGE
e_home = expected_score(r_home_adj, r_away)
e_away = 1.0 - e_home
# --------------------------------------------------------------
# Convert final score into Elo outcomes
# --------------------------------------------------------------
if hs > aas:
a_home, a_away = 1.0, 0.0
elif hs < aas:
a_home, a_away = 0.0, 1.0
else:
a_home, a_away = 0.5, 0.5
# --------------------------------------------------------------
# Update both underlying Elo ratings
# --------------------------------------------------------------
new_home = r_home + K * (a_home - e_home)
new_away = r_away + K * (a_away - e_away)
elo[home] = new_home
elo[away] = new_away
row.update({
"home_elo_pre": r_home,
"home_elo_post": new_home,
"away_elo_pre": r_away,
"away_elo_post": new_away,
})
rows.append(row)
# ------------------------------------------------------------------
# Create output DataFrame
# ------------------------------------------------------------------
df_elo = pl.DataFrame(rows)
df_elo.write_csv(GAME_LEVEL_OUTPUT_CSV)
df_elo.write_parquet(GAME_LEVEL_OUTPUT_PARQUET)
What Changed?
Although the full script looks very similar to the baseline implementation, only three conceptual changes have been introduced.
- We define a home advantage constant. This creates a temporary Elo adjustment that can be applied to the home team before calculating the expected probability.
- We calculate the expected probability using the adjusted home rating. The stored Elo ratings remain unchanged; only the expectation calculation uses the temporary adjustment.
- Neutral-site games skip the adjustment. If a game is marked as neutral, the home team's adjusted rating is simply its normal Elo rating, so the game behaves exactly like the baseline model.
The Elo update equations themselves do not change. Once the expected probabilities have been calculated, both teams are updated using the same method introduced in Article 1.
This is a useful example of how a small, carefully justified modelling change can represent an important real-world effect without making the overall algorithm difficult to understand.
Evaluating the Change
At this stage we have successfully incorporated home advantage into the Elo framework. The implementation is complete, but implementation alone does not tell us whether the change improves the model.
Every new modelling assumption should be viewed as a hypothesis rather than an automatic improvement. Some ideas that appear sensible genuinely improve a model, while others add unnecessary complexity or even reduce predictive performance.
Careful evaluation is the only reliable way to distinguish between the two.
"Every modelling assumption should earn its place through evidence."
In this article we established that home advantage exists in the historical data, showed how it can be represented within the Elo framework, and implemented that change with only a small modification to the original algorithm.
The next stage is to evaluate whether that adjustment produces a model that better reflects the behaviour of NFL teams over time and provides more realistic expectations before each game.
Key Takeaways
- Historical NFL results show a measurable home advantage.
- That evidence justifies representing home advantage within the Elo framework.
- Home advantage changes the expected probability of a game, not the underlying strength of a team.
- The underlying Elo ratings remain directly comparable across every team.
- Only a small modification to the baseline algorithm is required to incorporate the adjustment.
Next Steps
Home advantage is the first contextual factor added to our baseline Elo model, but it is unlikely to be the last.
So far, every victory has been treated equally. A one-point win and a thirty-point win produce exactly the same Elo update.
That raises another important modelling question:
"Does the margin of victory contain additional information about team strength?"
In the next article, Adding Margin of Victory to NFL Elo Ratings , we investigate whether incorporating winning margins allows the Elo model to respond more appropriately to dominant performances while avoiding excessive reactions to unusually large scorelines.