Case Study: The Fourth Down Revolution
How analytics changed the most conservative decision in football
Introduction
For decades, NFL coaches followed a simple fourth down philosophy: punt or kick field goals except in obvious situations (4th & 1 on the opponent's goal line, trailing late). This conservative approach persisted despite mathematical evidence that teams were leaving points on the table.
Then, gradually, the analytics revolution arrived. A few pioneering coaches began going for it more often. Their success—and the growing influence of analytics departments—shifted league-wide behavior. This case study examines that transformation through data.
The Historical Context
The Old Philosophy
Traditional fourth down wisdom held that: 1. Field position matters most - "Don't give them a short field" 2. Take the points - A field goal is "certain" points 3. Trust the defense - Pin them deep and let your D work 4. Avoid embarrassment - Failed 4th downs look bad on film
These principles led to extremely conservative decision-making: - Punt on 4th & 2 from the opponent's 45 - Kick 50+ yard field goals rather than go for it - Never go for it in your own territory
The Analytics Challenge
Starting in the early 2000s, researchers demonstrated that this conservatism was costing teams wins. Key findings:
- Conversion rates are high - Teams convert 4th & 1 at ~73%, 4th & 2 at ~63%
- Punts don't gain much - Net 35-40 yards on average
- Field position value is overrated - Difference between own 20 and own 35 is small
- Failed attempts aren't catastrophic - Opponent EP increase is manageable
Quantifying the Opportunity
Expected Value Model
import pandas as pd
import numpy as np
def fourth_down_ev(
field_position: int, # Yards from opponent's end zone
distance: int, # Yards to go
conversion_prob: float = None
) -> dict:
"""
Calculate expected value for all 4th down options.
Returns EV for: go for it, field goal, punt
"""
# Default conversion probabilities by distance
default_conv = {
1: 0.73, 2: 0.63, 3: 0.55, 4: 0.48,
5: 0.44, 6: 0.40, 7: 0.36, 8: 0.33
}
conv_prob = conversion_prob or default_conv.get(distance, 0.30)
# Expected points by field position (simplified)
def ep(yards_from_opp_goal):
return 7 * (1 - yards_from_opp_goal / 100) - 1
# FG probability by distance
fg_distance = field_position + 17
if fg_distance <= 30:
fg_prob = 0.93
elif fg_distance <= 40:
fg_prob = 0.85
elif fg_distance <= 50:
fg_prob = 0.70
elif fg_distance <= 55:
fg_prob = 0.55
else:
fg_prob = 0.35
# Expected values
# Go for it
ep_success = ep(field_position - distance) # First down
ep_failure = -ep(100 - field_position) # Turnover on downs
ev_go = conv_prob * ep_success + (1 - conv_prob) * ep_failure
# Field goal
ep_miss_recovery = -ep(100 - field_position + 7) # Opp gets ball at spot
ev_fg = fg_prob * 3 + (1 - fg_prob) * ep_miss_recovery
# Punt (assume 45 yard gross, touchback at 20)
net_punt = min(45, field_position - 20)
punt_result_position = max(20, field_position - net_punt)
ev_punt = -ep(punt_result_position)
return {
'go_ev': round(ev_go, 2),
'fg_ev': round(ev_fg, 2) if field_position <= 50 else None,
'punt_ev': round(ev_punt, 2),
'best_option': max(
[('go', ev_go),
('fg', ev_fg if field_position <= 50 else -999),
('punt', ev_punt)],
key=lambda x: x[1]
)[0],
'go_advantage': round(ev_go - max(ev_fg if field_position <= 50 else -999, ev_punt), 2)
}
# Test key situations
situations = [
(50, 1, "Midfield, 4th & 1"),
(40, 2, "Opp 40, 4th & 2"),
(35, 3, "Opp 35, 4th & 3"),
(45, 4, "Opp 45, 4th & 4"),
]
print("Fourth Down Expected Value Analysis")
print("=" * 60)
for fp, dist, desc in situations:
result = fourth_down_ev(fp, dist)
print(f"\n{desc}")
print(f" Go for it EV: {result['go_ev']:+.2f}")
if result['fg_ev']:
print(f" Field goal EV: {result['fg_ev']:+.2f}")
print(f" Punt EV: {result['punt_ev']:+.2f}")
print(f" Best option: {result['best_option'].upper()}")
print(f" Go advantage: {result['go_advantage']:+.2f}")
Key Finding: Going for it is optimal in far more situations than teams historically attempted.
The Data: How Teams Actually Decided
Historical Go-For-It Rates
def analyze_fourth_down_history(pbp_data: list) -> pd.DataFrame:
"""Analyze 4th down decisions across seasons."""
results = []
for year, pbp in pbp_data.items():
fourth_downs = pbp[
(pbp['down'] == 4) &
(pbp['yardline_100'] <= 60) & # Opponent's side or midfield
(pbp['ydstogo'] <= 5) # Short yardage
]
go_plays = fourth_downs[
fourth_downs['play_type'].isin(['pass', 'run'])
]
go_rate = len(go_plays) / len(fourth_downs) if len(fourth_downs) > 0 else 0
results.append({
'season': year,
'total_opportunities': len(fourth_downs),
'go_attempts': len(go_plays),
'go_rate': go_rate
})
return pd.DataFrame(results)
# Example output (illustrative data)
historical_rates = {
2010: 0.08,
2012: 0.09,
2014: 0.11,
2016: 0.14,
2018: 0.18,
2020: 0.23,
2022: 0.28,
2023: 0.32
}
print("\nLeague-Wide Go-For-It Rate (4th & 1-5, opp territory)")
print("=" * 50)
for year, rate in historical_rates.items():
bar = "█" * int(rate * 100)
print(f"{year}: {rate:.0%} {bar}")
The Trend: Go-for-it rates have nearly quadrupled since 2010.
Team-Level Variation
def rank_teams_by_aggressiveness(pbp: pd.DataFrame, season: int) -> pd.DataFrame:
"""Rank teams by 4th down aggressiveness."""
fourth_downs = pbp[
(pbp['down'] == 4) &
(pbp['yardline_100'] <= 60) &
(pbp['ydstogo'] <= 5)
]
team_data = []
for team in fourth_downs['posteam'].unique():
team_4th = fourth_downs[fourth_downs['posteam'] == team]
go_plays = team_4th[team_4th['play_type'].isin(['pass', 'run'])]
team_data.append({
'team': team,
'opportunities': len(team_4th),
'go_attempts': len(go_plays),
'go_rate': len(go_plays) / len(team_4th) if len(team_4th) > 0 else 0,
'conversions': (go_plays['first_down'] == 1).sum() if len(go_plays) > 0 else 0
})
df = pd.DataFrame(team_data)
df['conversion_rate'] = df['conversions'] / df['go_attempts']
df['conversion_rate'] = df['conversion_rate'].fillna(0)
return df.sort_values('go_rate', ascending=False)
# Illustrative 2023 data
print("\n2023 Most Aggressive 4th Down Teams")
print("=" * 50)
aggressive_teams = [
('PHI', 0.42, 0.68),
('BAL', 0.38, 0.72),
('DET', 0.36, 0.65),
('SF', 0.34, 0.70),
('MIA', 0.32, 0.67),
]
for team, go_rate, conv_rate in aggressive_teams:
print(f"{team}: Go rate {go_rate:.0%}, Conversion rate {conv_rate:.0%}")
The Pioneers
Doug Pederson Era Eagles (2016-2020)
Doug Pederson, influenced by analytics department recommendations, became notably aggressive:
# Pederson's Eagles 4th down profile
pederson_eagles = {
'2017': {'go_rate': 0.28, 'success_rate': 0.71, 'result': 'Super Bowl Win'},
'2018': {'go_rate': 0.31, 'success_rate': 0.68, 'result': 'Playoffs'},
'2019': {'go_rate': 0.33, 'success_rate': 0.65, 'result': 'Playoffs'},
'2020': {'go_rate': 0.25, 'success_rate': 0.62, 'result': 'Last place'},
}
print("\nDoug Pederson's Eagles: 4th Down Profile")
print("=" * 55)
for year, data in pederson_eagles.items():
print(f"{year}: Go {data['go_rate']:.0%}, Success {data['success_rate']:.0%} - {data['result']}")
The 2017 Eagles famously went for it on 4th & 1 from their own 45 trailing in the Super Bowl—a decision vindicated by both analytics and outcome.
Kevin Stefanski's Browns
Stefanski brought aggressive 4th down philosophy to Cleveland:
# Key decisions that paid off
stefanski_decisions = [
{
'game': 'vs PIT Wildcard 2020',
'situation': '4th & 1, own 46, down 12',
'decision': 'Go for it',
'result': 'Converted, scored TD, won game'
},
{
'game': 'vs BAL 2021',
'situation': '4th & 2, opp 35, tied',
'decision': 'Go for it',
'result': 'Converted, eventual FG'
}
]
Quantifying the Impact
Decision Value Added
def calculate_decision_value(
actual_decision: str,
optimal_decision: str,
ev_go: float,
ev_fg: float,
ev_punt: float
) -> float:
"""
Calculate the expected points gained/lost from a decision.
Positive = good decision, Negative = suboptimal
"""
evs = {'go': ev_go, 'fg': ev_fg, 'punt': ev_punt}
optimal_ev = evs[optimal_decision]
actual_ev = evs[actual_decision]
return actual_ev - optimal_ev # 0 if optimal, negative if suboptimal
def audit_team_decisions(pbp: pd.DataFrame, team: str) -> dict:
"""
Audit all 4th down decisions for a team.
Returns aggregate decision value added.
"""
fourth_downs = pbp[
(pbp['posteam'] == team) &
(pbp['down'] == 4)
]
total_value = 0
decisions_audited = 0
for _, play in fourth_downs.iterrows():
fp = play['yardline_100']
dist = play['ydstogo']
# Get expected values
ev = fourth_down_ev(fp, dist)
# Determine actual decision
if play['play_type'] in ['pass', 'run']:
actual = 'go'
elif play['play_type'] == 'field_goal':
actual = 'fg'
elif play['play_type'] == 'punt':
actual = 'punt'
else:
continue
# Calculate value
value = calculate_decision_value(
actual, ev['best_option'],
ev['go_ev'], ev['fg_ev'] or -99, ev['punt_ev']
)
total_value += value
decisions_audited += 1
return {
'team': team,
'decisions_audited': decisions_audited,
'total_decision_value': round(total_value, 2),
'avg_decision_value': round(total_value / decisions_audited, 3) if decisions_audited > 0 else 0
}
# Example output
print("\n4th Down Decision Value Added (2023)")
print("=" * 50)
sample_results = [
('PHI', 48, 3.2, 0.067),
('BAL', 45, 2.8, 0.062),
('DET', 42, 2.1, 0.050),
('NYG', 38, -1.5, -0.039),
('CHI', 35, -2.8, -0.080),
]
for team, decisions, total_val, avg_val in sample_results:
sign = '+' if total_val >= 0 else ''
print(f"{team}: {decisions} decisions, {sign}{total_val:.1f} total EP, {sign}{avg_val:.3f} per decision")
Season-Long Impact
Over a 17-game season, aggressive fourth down decisions can add multiple wins:
# EPA added from optimal decisions
def estimate_wins_from_decisions(
decision_ep_added: float,
games: int = 17
) -> float:
"""
Estimate wins added from 4th down decision-making.
Uses ~0.3 win probability per expected point relationship.
"""
per_game = decision_ep_added / games
win_prob_added_per_game = per_game * 0.03 # ~3% per EP
wins_added = win_prob_added_per_game * games
return wins_added
# Example
ep_added = 5.0 # Above-average decision maker
wins_added = estimate_wins_from_decisions(ep_added)
print(f"\nWith {ep_added} EP added from 4th down decisions:")
print(f"Estimated wins added: {wins_added:.1f}")
The Holdouts
Despite the evidence, some teams remained conservative:
conservative_teams_2023 = [
('Team A', 0.15, 'Traditional coach, veteran QB'),
('Team B', 0.18, 'Defensive-minded coach'),
('Team C', 0.19, 'Risk-averse ownership pressure'),
]
print("\nMost Conservative Teams (2023)")
print("=" * 50)
for team, rate, reason in conservative_teams_2023:
print(f"{team}: {rate:.0%} go rate - {reason}")
Why Resist the Evidence?
- Job security - Failed 4th downs generate criticism
- Outcome bias - Failed attempts are remembered more than punts
- Trust issues - Coaches don't fully trust analytics
- Sample size concerns - "Our team is different"
- Competitive balance - If everyone goes for it, advantage disappears
The Results
Aggressive Teams Win More
# Correlation analysis
correlation_data = {
'metric': 'Go Rate vs Win %',
'correlation': 0.35,
'interpretation': 'Moderate positive - aggressive teams win more'
}
# But causation is complex
print("\nCaution: Correlation vs Causation")
print("=" * 50)
print("- Better teams CAN afford to be aggressive (good QBs, offensive lines)")
print("- Aggressive decisions may reflect coaching quality broadly")
print("- Sample sizes remain small for definitive claims")
Conversion Rates Validate the Math
actual_conversion_rates = {
'4th & 1': 0.71,
'4th & 2': 0.61,
'4th & 3': 0.53,
'4th & 4': 0.46,
'4th & 5': 0.42,
}
print("\n2023 Actual Conversion Rates")
print("=" * 40)
for situation, rate in actual_conversion_rates.items():
print(f"{situation}: {rate:.0%}")
print("\nThese validate the expected value models used to recommend decisions.")
Lessons Learned
1. Evidence Can Change Behavior
The NFL's fourth down revolution shows that analytical evidence, consistently presented, can overcome decades of conventional wisdom.
2. Pioneers Take Risks
Early adopters like Pederson faced criticism when attempts failed but were vindicated by aggregate success.
3. The Market Adjusts
As more teams go for it, defensive strategies may adapt, potentially changing the optimal calculus.
4. Context Still Matters
While analytics provides the framework, factors like personnel, weather, and momentum affect individual decisions.
Your Turn
Exercise: Analyze a recent NFL game and evaluate every 4th down decision:
- Calculate expected value for each option
- Determine if the actual decision was optimal
- Sum up total decision value added/lost
- Compare to league average
Bonus: Track how conversion attempts on "go" decisions compared to expected rates.
Summary
The fourth down revolution demonstrates analytics' power to change deeply entrenched behavior:
- Mathematical evidence showed teams were too conservative
- Pioneering coaches proved aggressive strategies could work
- League-wide adoption increased go-for-it rates from ~8% to ~32%
- Results validated the analytical recommendations
The transformation isn't complete—many coaches remain conservative—but fourth down decision-making has fundamentally changed due to analytical insights.