9 min read

Injuries are the great equalizer in the NFL. A team built to dominate can be brought low by key absences, while an underdog can find opportunity when opponents lose crucial players. For analysts, injuries represent both a challenge and an...

Chapter 23: Injuries and Their Impact

Part 5: Advanced Topics


Learning Objectives

By the end of this chapter, you will be able to:

  1. Quantify the impact of player injuries on team performance
  2. Build injury adjustment models for prediction systems
  3. Understand position-specific injury importance
  4. Analyze injury report information and practice participation
  5. Incorporate uncertainty around injury status into predictions

Introduction: The Injury Factor

Injuries are the great equalizer in the NFL. A team built to dominate can be brought low by key absences, while an underdog can find opportunity when opponents lose crucial players. For analysts, injuries represent both a challenge and an opportunity: they introduce uncertainty that must be modeled, but they also create inefficiencies in prediction markets when injury impacts are mispriced.

This chapter develops a systematic framework for quantifying injury impacts. We move beyond simple "star player out = bad" intuition to precise estimates of how specific player absences affect team performance.


23.1 The Challenge of Injury Analysis

Why Injuries Are Difficult to Model

Injuries present unique analytical challenges:

Information Uncertainty - Injury reports are often vague ("questionable") - Game-time decisions create last-minute uncertainty - Severity is rarely disclosed accurately - Recovery timelines are unpredictable

Contextual Complexity - Impact depends on the opponent - Backup quality varies dramatically - Scheme may adjust around absences - Other injuries may compound effects

Sample Size Issues - Star players rarely miss games - Each injury situation is unique - Limited historical comparable situations

The Injury Report System

The NFL requires teams to submit injury reports following specific guidelines:

Designation Meanings:

Designation Historical Game Play Rate Interpretation
Out 0% Definitely not playing
Doubtful ~25% Unlikely to play
Questionable ~50-60% Uncertain status
Probable* ~90% Likely to play
No designation ~95%+ Expected to play

Note: "Probable" was removed from NFL reports in 2016, but the concept remains useful.

Practice Participation: - Full: Full participation in practice - Limited: Partial participation - DNP: Did not practice

Practice patterns provide signal: - Full → Full → Full: Very likely to play - DNP → DNP → Limited: Concerning - DNP → DNP → DNP → Questionable: Often game-time decision


23.2 Position Value Framework

Not All Positions Are Equal

The first step in injury analysis is understanding that positions have vastly different impacts on team performance. A starting quarterback's absence affects a team differently than a starting guard's absence.

Quarterback Value

Quarterbacks have outsized importance:

Approximate point spread impact of QB change:
- Elite QB to average backup: 4-7 points
- Good starter to backup: 3-5 points
- Average starter to backup: 2-4 points

Historical Examples:

Starter Backup Spread Impact
Patrick Mahomes Chad Henne ~6 points
Aaron Rodgers Jordan Love (early) ~5 points
Tua Tagovailoa Skylar Thompson ~4 points
Brock Purdy Josh Johnson ~3.5 points

QB backup quality varies enormously, making quarterback injuries particularly difficult to assess.

Position Importance Hierarchy

Based on historical analysis of injury impacts:

Tier 1 - Highest Impact (3+ points): - Quarterback - Left Tackle (protecting QB blind side)

Tier 2 - High Impact (1-2 points): - Edge Rusher (premier pass rushers) - Cornerback #1 - Wide Receiver #1 - Running Back (elite three-down backs)

Tier 3 - Moderate Impact (0.5-1 point): - Interior Defensive Line - Linebacker (coverage specialists) - Safety - Interior Offensive Line

Tier 4 - Lower Impact (<0.5 points): - Wide Receiver #2-3 - Tight End (depending on scheme) - Depth positions - Special teams (except kicker/punter)

Calculating Position Value

A useful framework for position value:

Position Impact = Player Value - Replacement Value

Where:
- Player Value: Contribution when playing (EPA, WAR, etc.)
- Replacement Value: Expected contribution from backup

Example Calculation:

Starter EPA per game: +5.2 Expected backup EPA per game: +1.8 Position Impact = 5.2 - 1.8 = 3.4 EPA

Converting to points: 3.4 EPA ≈ 2.0 point spread impact


23.3 Quantifying Player Value

Wins Above Replacement (WAR)

WAR provides a comprehensive player value metric:

WAR = (Player EPA - Replacement EPA) / EPA_per_Win

Typical EPA per Win ≈ 25-30 EPA

2023 Positional WAR Leaders (examples):

Position Player Approx WAR
QB Lamar Jackson 8.2
WR CeeDee Lamb 2.8
Edge Myles Garrett 2.5
CB Sauce Gardner 2.2
RB Christian McCaffrey 2.1

Converting WAR to Game Impact

For single-game analysis:

Per Game Impact = Season WAR / 17

Elite QB (~8 WAR): 0.47 wins per game
Elite WR (~3 WAR): 0.18 wins per game
Elite CB (~2 WAR): 0.12 wins per game

Converting to spread impact (1 point ≈ 0.03 wins):

Elite QB: 0.47 / 0.03 ≈ 15.7 points over replacement
But we compare to backup, not replacement level:
Adjusted Impact = WAR_per_game × Quality_Differential

Expected Points Added (EPA) Framework

EPA provides game-level precision:

def calculate_injury_impact_epa(player_epa_per_play, plays_per_game,
                                 backup_epa_per_play):
    """
    Calculate expected impact from player absence.

    Args:
        player_epa_per_play: Starter's EPA contribution
        plays_per_game: Expected plays for position
        backup_epa_per_play: Backup's expected EPA

    Returns:
        Expected point swing from injury
    """
    starter_contribution = player_epa_per_play * plays_per_game
    backup_contribution = backup_epa_per_play * plays_per_game

    epa_impact = starter_contribution - backup_contribution

    # Convert EPA to points (rough 1:1 for offense)
    return epa_impact

Example: Elite Wide Receiver Absence

  • Starter EPA/play: +0.15 (elite)
  • Expected targets per game: 10
  • Backup EPA/play: +0.02 (average)

Impact = (0.15 - 0.02) × 10 = 1.3 expected points


23.4 Building an Injury Adjustment Model

The Comprehensive Model

A complete injury adjustment considers multiple factors:

Total Adjustment = Σ (Position_Weight × Player_Value × Play_Probability)

Where:
- Position_Weight: Importance of position (0-1 scale)
- Player_Value: Individual's value above backup
- Play_Probability: Likelihood of not playing (0-1)

Step 1: Establish Position Weights

Based on historical variance explained:

Position Weight Rationale
QB 1.00 Maximum impact
LT 0.35 Protects QB
Edge 0.30 Pass rush crucial
CB1 0.25 Coverage importance
WR1 0.25 Receiving threat
RB 0.20 Variable by scheme
Interior OL 0.15 Important but fungible
TE 0.15 Scheme dependent
Other 0.10 Lower impact

Step 2: Calculate Player Value Over Backup

For each player, estimate value differential:

def player_value_differential(player_stats, backup_stats, league_average):
    """
    Calculate how much better the starter is than backup.

    Returns value on -5 to +5 point scale
    """
    # Normalize to z-scores
    player_z = (player_stats - league_average) / league_std
    backup_z = (backup_stats - league_average) / league_std

    differential_z = player_z - backup_z

    # Convert to point scale (each z ≈ 1.5 points for QB, less for others)
    return differential_z * position_conversion_factor

Step 3: Apply Probability Adjustments

Convert injury status to probability:

def injury_probability(designation, practice_pattern):
    """
    Estimate probability player misses game.

    Args:
        designation: 'out', 'doubtful', 'questionable', etc.
        practice_pattern: List of ['full', 'limited', 'dnp']

    Returns:
        Probability of not playing (0-1)
    """
    base_probabilities = {
        'out': 1.00,
        'doubtful': 0.75,
        'questionable': 0.40,
        'probable': 0.10,
        'none': 0.05
    }

    base_prob = base_probabilities.get(designation, 0.5)

    # Adjust for practice pattern
    practice_adjustment = calculate_practice_adjustment(practice_pattern)

    return min(1.0, base_prob + practice_adjustment)

Step 4: Aggregate Team Impact

Sum individual impacts:

def total_injury_adjustment(injuries, team_side):
    """
    Calculate total spread adjustment for all injuries.

    Args:
        injuries: List of (position, player_value, probability)
        team_side: 'home' or 'away'

    Returns:
        Spread adjustment in points
    """
    total_adjustment = 0

    for position, player_value, miss_probability in injuries:
        position_weight = POSITION_WEIGHTS[position]
        impact = position_weight * player_value * miss_probability
        total_adjustment += impact

    # Positive adjustment = team gets worse
    if team_side == 'home':
        return total_adjustment  # Add to spread
    else:
        return -total_adjustment  # Subtract from spread

23.5 Quarterback Injury Deep Dive

The Special Case of Quarterbacks

Quarterback injuries deserve special treatment due to their outsized impact:

QB Injury Impact = f(Starter_Quality, Backup_Quality, Scheme_Dependence)

Starter Quality Tiers

Tier Examples Approximate Value
Elite Mahomes, Allen +4 to +6 points
Good Burrow, Herbert +3 to +4 points
Average Cousins, Goff +1 to +2 points
Below Average Various 0 to +1 points

Backup Quality Assessment

Backup quarterbacks fall into categories:

Quality Backup (+1 to +2 points over replacement) - Experienced NFL starter - Former high draft pick with starts - Veteran with system knowledge

Average Backup (replacement level) - Career backup - Limited starting experience - Adequate but not impactful

Below Replacement (-1 to -2 points) - Undrafted emergency option - Practice squad elevation - Very limited experience

The Uncertainty Factor

Backup performance is highly variable:

Backup QB Performance Distribution:
- Mean: Approximately 0 (replacement level)
- Standard Deviation: 0.5 EPA/dropback

This means outcome range is wide:
- 10th percentile: Disaster (-0.64 EPA/db)
- 50th percentile: Mediocre (0.00 EPA/db)
- 90th percentile: Surprisingly good (+0.64 EPA/db)

This variance should widen confidence intervals for games with backup QBs.


23.6 Multiple Injury Scenarios

Compounding Effects

When multiple players are injured, effects may compound:

Offensive Line Example: - One lineman out: ~0.5 point impact - Two linemen out: ~1.5 point impact (not 1.0) - Three linemen out: ~3.0+ point impact

The non-linear relationship reflects that: - Communication becomes harder - Protection schemes break down - Backup quality drops with depth

Modeling Compound Effects

def compound_injury_adjustment(injuries_by_position):
    """
    Calculate adjustment accounting for compound effects.

    Args:
        injuries_by_position: Dict mapping position to injury count

    Returns:
        Adjusted impact including compound effects
    """
    base_impact = 0
    compound_multiplier = 1.0

    for position, count in injuries_by_position.items():
        # Base impact
        base = POSITION_WEIGHTS[position] * count
        base_impact += base

        # Compound effect for multiple at same position group
        if count > 1:
            compound_multiplier *= (1 + 0.2 * (count - 1))

    # Position group interactions
    if 'OL' in injuries_by_position and 'QB' not in injuries_by_position:
        # QB faces more pressure, implicit impact
        compound_multiplier *= 1.1

    return base_impact * compound_multiplier

Injury Correlation

Some injuries are correlated:

Within-Game Correlation: - Physical games lead to more injuries - Defensive injuries may cluster - Offensive line injuries cascade

Historical Correlation: - Teams with poor medical staff have more injuries - Artificial turf associated with specific injuries - Age correlates with injury risk


23.7 Game-Time Decision Analysis

The "Questionable" Problem

"Questionable" designations create analytical challenges:

  • 40-60% play rate historically
  • Wide range of conditions
  • Game-time announcements
  • May play but limited

Modeling Uncertainty

For game-time decisions, model two scenarios:

def gameday_injury_analysis(questionable_players, model):
    """
    Analyze game accounting for questionable players.

    Returns projections for different scenarios.
    """
    scenarios = {}

    # Generate all combinations
    for combo in itertools.product([True, False], repeat=len(questionable_players)):
        scenario_injuries = [p for p, plays in zip(questionable_players, combo) if not plays]

        adjustment = calculate_adjustment(scenario_injuries)
        probability = calculate_scenario_probability(combo, questionable_players)

        scenarios[combo] = {
            'adjustment': adjustment,
            'probability': probability
        }

    # Expected adjustment
    expected = sum(s['adjustment'] * s['probability'] for s in scenarios.values())

    # Variance in outcomes
    variance = sum(s['probability'] * (s['adjustment'] - expected)**2
                  for s in scenarios.values())

    return {
        'expected_adjustment': expected,
        'std_adjustment': np.sqrt(variance),
        'scenarios': scenarios
    }

Practice Report Signals

Practice participation provides signal:

Pattern Play Rate Interpretation
F-F-F 95%+ Almost certain to play
L-L-F 85% Likely to play
L-L-L 60% Uncertain
D-D-L 40% Concerning
D-D-D 20% Unlikely

23.8 In-Game Injury Adjustments

When Injuries Occur During Games

Mid-game injuries require live adjustment:

def ingame_injury_adjustment(player, time_remaining, current_score_differential):
    """
    Adjust win probability for in-game injury.

    Args:
        player: Injured player information
        time_remaining: Seconds remaining in game
        current_score_differential: Current score difference

    Returns:
        Win probability adjustment
    """
    # Base impact
    player_value = calculate_player_value(player)

    # Time-weighted impact (less time = less impact)
    time_factor = time_remaining / 3600  # Proportion of game remaining

    # Score context (injuries matter more in close games)
    score_factor = 1.0 / (1 + abs(current_score_differential) / 14)

    impact = player_value * time_factor * score_factor

    return impact

Historical In-Game Impact

Analysis of in-game quarterback injuries:

Time of Injury WP Impact Notes
1st Quarter -8% to -15% Full impact
2nd Quarter -6% to -12% Significant
3rd Quarter -4% to -10% Still meaningful
4th Quarter -2% to -8% Context dependent

23.9 Injury Recovery and Return Analysis

Return Timeline Expectations

Different injuries have different recovery patterns:

Injury Type Typical Recovery Variance
Concussion 1-2 weeks High (protocol)
Hamstring 2-4 weeks Moderate
High ankle sprain 4-6 weeks High
MCL sprain 4-8 weeks Moderate
ACL tear 9-12 months Low

Performance After Return

Players returning from injury often underperform initially:

First Game Back Performance (relative to baseline):
- Soft tissue: -15% to -25%
- Concussion: -5% to -15%
- ACL (first year back): -10% to -20%

Modeling Return Impact

def returned_player_adjustment(player, injury_type, games_since_return):
    """
    Adjust player value for recent return from injury.

    Args:
        player: Player information
        injury_type: Type of injury returned from
        games_since_return: Games played since return

    Returns:
        Adjusted player value
    """
    base_value = player['normal_value']

    # Recovery factors by injury type
    recovery_rates = {
        'soft_tissue': 0.85,  # Initial performance
        'concussion': 0.90,
        'structural': 0.75
    }

    initial_rate = recovery_rates.get(injury_type, 0.85)

    # Gradual recovery over games
    games_to_full = {'soft_tissue': 3, 'concussion': 2, 'structural': 8}
    recovery_games = games_to_full.get(injury_type, 4)

    recovery_factor = min(1.0, initial_rate + (1 - initial_rate) *
                         games_since_return / recovery_games)

    return base_value * recovery_factor

23.10 Market Response to Injuries

How Markets Price Injuries

Betting markets incorporate injury information:

Immediate Response: - Major QB injury: 3-5 point line movement - Star player: 1-2 point movement - Role player: 0.5 or less

Information Flow: - Official report: Full market adjustment - Social media rumors: Partial adjustment - Game-time announcement: Final adjustment

Finding Value in Injury Markets

Markets may misprice injuries when:

  1. Overreaction to star names - Backup quality underestimated - Scheme adjustment capability ignored

  2. Underreaction to depth - Multiple injuries not fully compounded - Practice squad usage not anticipated

  3. Timing differences - Early week information not fully priced - Game-time status creates opportunities

Tracking Market Efficiency

def analyze_injury_market_efficiency(games_df):
    """
    Analyze how well markets price injuries.

    Args:
        games_df: DataFrame with injury info, lines, results

    Returns:
        Analysis of market efficiency
    """
    results = {
        'qb_injuries': {'ats_record': [], 'clv': []},
        'multiple_injuries': {'ats_record': [], 'clv': []},
        'game_time_decisions': {'ats_record': [], 'clv': []}
    }

    for _, game in games_df.iterrows():
        # Categorize game
        if game['qb_out']:
            category = 'qb_injuries'
        elif game['total_injuries'] >= 3:
            category = 'multiple_injuries'
        elif game['game_time_decision']:
            category = 'game_time_decisions'
        else:
            continue

        # Track results
        results[category]['ats_record'].append(game['covered'])
        results[category]['clv'].append(game['clv'])

    return results

23.11 Building a Complete Injury Model

Putting It All Together

A comprehensive injury adjustment system:

class NFLInjuryModel:
    """Complete injury impact model."""

    def __init__(self, player_values, backup_values, position_weights):
        self.player_values = player_values
        self.backup_values = backup_values
        self.position_weights = position_weights

    def calculate_team_adjustment(self, team, injuries):
        """
        Calculate total injury adjustment for a team.

        Args:
            team: Team identifier
            injuries: List of injury information

        Returns:
            Spread adjustment in points
        """
        total_adjustment = 0
        position_counts = {}

        for injury in injuries:
            player = injury['player']
            status = injury['status']
            position = injury['position']

            # Get miss probability
            miss_prob = self._get_miss_probability(status, injury.get('practice', []))

            # Get player value differential
            starter_value = self.player_values.get(player, 0)
            backup_value = self.backup_values.get(f"{team}_{position}_backup", 0)
            differential = starter_value - backup_value

            # Apply position weight
            weight = self.position_weights.get(position, 0.1)

            # Calculate impact
            impact = weight * differential * miss_prob
            total_adjustment += impact

            # Track for compound effects
            pos_group = self._get_position_group(position)
            position_counts[pos_group] = position_counts.get(pos_group, 0) + miss_prob

        # Apply compound multiplier
        compound = self._calculate_compound_effect(position_counts)

        return total_adjustment * compound

    def _get_miss_probability(self, status, practice_pattern):
        """Convert status and practice to miss probability."""
        base = {'out': 1.0, 'doubtful': 0.75, 'questionable': 0.45}
        prob = base.get(status.lower(), 0.05)

        # Adjust for practice
        if practice_pattern:
            if practice_pattern[-1] == 'full':
                prob *= 0.6
            elif practice_pattern[-1] == 'dnp':
                prob *= 1.3

        return min(1.0, prob)

    def _get_position_group(self, position):
        """Map position to group for compound effects."""
        groups = {
            'LT': 'OL', 'LG': 'OL', 'C': 'OL', 'RG': 'OL', 'RT': 'OL',
            'DE': 'DL', 'DT': 'DL',
            'CB': 'secondary', 'S': 'secondary', 'FS': 'secondary', 'SS': 'secondary'
        }
        return groups.get(position, position)

    def _calculate_compound_effect(self, position_counts):
        """Calculate multiplier for compound injuries."""
        multiplier = 1.0

        for group, count in position_counts.items():
            if count > 1:
                multiplier *= (1 + 0.15 * (count - 1))

        return min(2.0, multiplier)  # Cap at 2x

Validation Approach

Test injury model against historical data:

Validation Metrics:
1. Does adjustment correlate with actual margin impact?
2. Does adjustment improve model accuracy?
3. How does adjustment compare to market response?

23.12 Case Study: High-Profile Injury Impact

Example: Elite Quarterback Injury

Scenario: Team's franchise QB suffers season-ending injury in Week 8

Pre-Injury Status: - Team record: 6-1 - Point differential: +78 - Playoff probability: 95% - Super Bowl odds: 12%

Immediate Analysis:

  1. Backup assessment: - Career stats: 4 starts, 1-3 record - EPA/play: -0.08 (below average) - Experience in system: 3 years

  2. Model adjustment: - Starter value: +6.5 points above replacement - Backup value: -1.5 points vs replacement - Differential: 8.0 points - Position weight: 1.0 - Spread adjustment: +8.0 points

  3. Season projection update: - Expected wins rest of season: from 7.5 to 4.2 - Playoff probability: from 95% to 45% - Super Bowl odds: from 12% to 0.5%

Actual Results: - Team went 3-6 remainder - Average margin: -4.2 points - Model predicted margin shift: -8.0 points - Actual shift: -7.5 points

The model slightly overstated the impact, but was within reasonable error bounds.


Summary

Injury analysis requires:

  1. Position Value Framework - Understanding which positions matter most
  2. Player Valuation - Quantifying individual value over backups
  3. Probability Assessment - Converting injury status to miss probability
  4. Compound Effects - Accounting for multiple injury interactions
  5. Uncertainty Modeling - Widening confidence intervals for uncertain situations

Key principles: - Quarterbacks have outsized impact - Backup quality matters as much as starter quality - Multiple injuries compound non-linearly - Markets generally price injuries efficiently but not perfectly - Game-time decisions require scenario analysis


Key Formulas

Position Impact:

Impact = Position_Weight × (Starter_Value - Backup_Value) × Miss_Probability

QB Adjustment (simplified):

Adjustment = Starter_Tier - Backup_Tier
Where tiers range from +6 (elite) to -2 (emergency)

Compound Effect:

Compound_Multiplier = Π(1 + 0.15 × (n_injuries_in_group - 1))

Practice Problems

  1. A team's starting quarterback (elite tier) is listed as doubtful. The backup is a career backup with limited experience. Calculate the expected spread adjustment.

  2. Three offensive linemen are listed as questionable for the same team. How should you model the compound effect?

  3. A star wide receiver is returning from a hamstring injury after missing two weeks. How should you adjust his expected value for his first game back?


Chapter 23 Summary

Injuries represent one of the most important factors in NFL prediction. A systematic approach to injury analysis involves quantifying position importance, measuring player value differentials, assessing miss probabilities, and accounting for compound effects. While betting markets are generally efficient at pricing injuries, opportunities exist when injury impacts are over- or under-estimated.


Looking Ahead

Chapter 24 explores Weather Effects on NFL games. We'll examine how temperature, wind, precipitation, and altitude affect game outcomes, and develop models to incorporate weather into predictions.