Exercises: Traditional Football Statistics

Practice calculating, analyzing, and interpreting traditional football statistics.


Level 1: Foundation (Exercises 1.1-1.8)

Exercise 1.1: Basic Counting Statistics

Given the following game data for a running back, calculate the basic statistics:

rushing_plays = [4, 7, -2, 12, 3, 8, 1, 15, 5, 2, 6, -1, 9, 4, 3, 22, 5, 1, 8, 6]

Calculate: 1. Total rushing yards 2. Number of carries 3. Yards per carry 4. Longest run 5. Number of runs of 10+ yards


Exercise 1.2: Passing Statistics

A quarterback has the following game statistics: - Completions: 24 - Attempts: 38 - Passing yards: 312 - Touchdowns: 3 - Interceptions: 1

Calculate: 1. Completion percentage 2. Yards per attempt 3. Touchdown percentage 4. Interception percentage


Exercise 1.3: Team Totals

Calculate team offensive totals from these individual stats:

passing = {'yards': 285, 'tds': 2, 'attempts': 35}
rushing = {'yards': 156, 'tds': 1, 'attempts': 28}

Calculate: 1. Total offensive yards 2. Total offensive touchdowns 3. Total offensive plays 4. Yards per play


Exercise 1.4: First Down Calculation

Given play-by-play data, determine which plays resulted in first downs:

plays = [
    {'down': 1, 'distance': 10, 'yards': 4},
    {'down': 2, 'distance': 6, 'yards': 8},   # First down?
    {'down': 1, 'distance': 10, 'yards': 12}, # First down?
    {'down': 3, 'distance': 5, 'yards': 3},
    {'down': 4, 'distance': 2, 'yards': 3},   # First down?
]

Tasks: 1. Identify which plays resulted in first downs 2. Calculate first down percentage


Exercise 1.5: Turnover Margin

Team A and Team B have the following turnover statistics:

Team Interceptions Thrown Fumbles Lost Interceptions Caught Fumbles Recovered
A 2 1 3 0
B 1 2 1 2

Calculate: 1. Turnovers committed by each team 2. Turnovers forced by each team 3. Turnover margin for each team 4. Which team had the advantage?


Exercise 1.6: Third Down Efficiency

A team faced the following third down situations:

third_downs = [
    {'distance': 3, 'result': 'first_down'},
    {'distance': 8, 'result': 'incomplete'},
    {'distance': 1, 'result': 'first_down'},
    {'distance': 12, 'result': 'sack'},
    {'distance': 5, 'result': 'first_down'},
    {'distance': 7, 'result': 'incomplete'},
    {'distance': 2, 'result': 'first_down'},
    {'distance': 15, 'result': 'first_down'},
]

Calculate: 1. Third down attempts 2. Third down conversions 3. Third down conversion percentage 4. Conversion rate for short (1-3), medium (4-7), and long (8+) distances


Exercise 1.7: Red Zone Statistics

A team had 5 red zone trips with these results: - Trip 1: Touchdown - Trip 2: Field Goal - Trip 3: Touchdown - Trip 4: Turnover (interception) - Trip 5: Field Goal

Calculate: 1. Red zone scoring percentage 2. Red zone touchdown percentage 3. Points scored in red zone 4. Points per red zone trip


Exercise 1.8: Per-Game Averages

Convert these season totals to per-game averages (13-game season):

season_stats = {
    'passing_yards': 3456,
    'rushing_yards': 2145,
    'points_scored': 455,
    'first_downs': 286,
    'turnovers': 18
}

Level 2: Application (Exercises 2.1-2.6)

Exercise 2.1: Quarterback Comparison

Compare these two quarterbacks and determine which had the better season:

QB A: - 312 completions, 478 attempts, 3,845 yards, 32 TDs, 8 INTs

QB B: - 245 completions, 385 attempts, 3,212 yards, 28 TDs, 5 INTs

Tasks: 1. Calculate completion %, YPA, TD%, INT% for each 2. Calculate passer rating for each 3. Which QB was more efficient? Which had more production?


Exercise 2.2: Rushing Attack Analysis

Analyze this team's rushing performance by runner:

rushers = {
    'RB1': {'carries': 185, 'yards': 892, 'tds': 8, 'long': 45},
    'RB2': {'carries': 98, 'yards': 456, 'tds': 5, 'long': 32},
    'QB': {'carries': 65, 'yards': 312, 'tds': 4, 'long': 28},
    'WR1': {'carries': 12, 'yards': 78, 'tds': 1, 'long': 22}
}

Calculate for each rusher and team total: 1. Yards per carry 2. Percentage of team carries 3. Percentage of team rushing yards 4. Touchdowns per carry


Exercise 2.3: Receiving Corps Analysis

Analyze this team's receiving production:

receivers = {
    'WR1': {'targets': 125, 'receptions': 82, 'yards': 1156, 'tds': 9},
    'WR2': {'targets': 95, 'receptions': 58, 'yards': 756, 'tds': 5},
    'TE': {'targets': 68, 'receptions': 52, 'yards': 548, 'tds': 4},
    'RB1': {'targets': 45, 'receptions': 38, 'yards': 285, 'tds': 2},
    'WR3': {'targets': 42, 'receptions': 25, 'yards': 312, 'tds': 3}
}

Calculate for each receiver: 1. Catch rate 2. Yards per reception 3. Yards per target 4. Target share percentage


Exercise 2.4: Defensive Statistics

Calculate team defensive statistics from opponent offensive data:

games_allowed = [
    {'opp': 'Team A', 'points': 24, 'yards': 385, 'pass_yds': 245, 'rush_yds': 140},
    {'opp': 'Team B', 'points': 17, 'yards': 298, 'pass_yds': 198, 'rush_yds': 100},
    {'opp': 'Team C', 'points': 31, 'yards': 425, 'pass_yds': 312, 'rush_yds': 113},
    {'opp': 'Team D', 'points': 14, 'yards': 256, 'pass_yds': 156, 'rush_yds': 100},
    {'opp': 'Team E', 'points': 28, 'yards': 378, 'pass_yds': 228, 'rush_yds': 150}
]

Calculate: 1. Points allowed per game 2. Total yards allowed per game 3. Passing yards allowed per game 4. Rushing yards allowed per game


Exercise 2.5: Special Teams Evaluation

Evaluate this kicker's season:

field_goals = [
    {'distance': 25, 'made': True},
    {'distance': 42, 'made': True},
    {'distance': 38, 'made': False},
    {'distance': 33, 'made': True},
    {'distance': 48, 'made': True},
    {'distance': 51, 'made': False},
    {'distance': 29, 'made': True},
    {'distance': 44, 'made': True},
    {'distance': 37, 'made': True},
    {'distance': 52, 'made': False}
]
extra_points = {'attempts': 45, 'made': 44}

Calculate: 1. Overall field goal percentage 2. FG% by distance range (under 40, 40-49, 50+) 3. Extra point percentage 4. Total points from kicking


Exercise 2.6: Box Score Analysis

Given this box score data, determine the winner and key statistical advantages:

home_team = {
    'score': 31,
    'first_downs': 24,
    'total_yards': 425,
    'passing_yards': 285,
    'rushing_yards': 140,
    'turnovers': 2,
    'time_of_possession': '32:15',
    'third_down': '7/14',
    'penalties': 8,
    'penalty_yards': 65
}

away_team = {
    'score': 28,
    'first_downs': 21,
    'total_yards': 398,
    'passing_yards': 312,
    'rushing_yards': 86,
    'turnovers': 1,
    'time_of_possession': '27:45',
    'third_down': '5/12',
    'penalties': 5,
    'penalty_yards': 42
}

Analysis: 1. Which team won and by how much? 2. Calculate yards per play for each team 3. Which team was more efficient on third down? 4. Did the team with fewer turnovers win?


Level 3: Intermediate (Exercises 3.1-3.5)

Exercise 3.1: Passer Rating Calculator

Implement the NFL passer rating formula:

def calculate_passer_rating(completions: int, attempts: int,
                             yards: int, touchdowns: int,
                             interceptions: int) -> float:
    """
    Calculate NFL passer rating.

    Formula:
    a = ((Comp/Att * 100) - 30) / 20
    b = ((Yards/Att) - 3) / 4
    c = (TD/Att) * 20
    d = 2.375 - ((Int/Att) * 25)

    Each component capped at 0 and 2.375
    Rating = ((a + b + c + d) / 6) * 100
    """
    pass  # Implement this

Test with: - Perfect rating scenario: 10/10, 400 yards, 4 TDs, 0 INTs - Average QB: 22/35, 250 yards, 2 TDs, 1 INT - Poor performance: 15/32, 145 yards, 0 TDs, 3 INTs


Exercise 3.2: Season Statistics Aggregator

Build a function to aggregate game-by-game stats into season totals:

games = [
    {'week': 1, 'yards': 285, 'tds': 2, 'attempts': 35, 'completions': 22},
    {'week': 2, 'yards': 312, 'tds': 3, 'attempts': 42, 'completions': 28},
    {'week': 3, 'yards': 198, 'tds': 1, 'attempts': 28, 'completions': 18},
    # ... more games
]

def aggregate_season_stats(games: list) -> dict:
    """
    Aggregate game stats into season totals and calculate rates.

    Returns:
    - Total yards, TDs, attempts, completions
    - Season completion %, YPA
    - Per-game averages
    """
    pass  # Implement this

Exercise 3.3: Opponent-Adjusted Statistics

Adjust a team's statistics based on opponent strength:

games = [
    {'opponent': 'Team A', 'opp_def_rank': 5, 'yards_gained': 350},
    {'opponent': 'Team B', 'opp_def_rank': 45, 'yards_gained': 425},
    {'opponent': 'Team C', 'opp_def_rank': 120, 'yards_gained': 520},
    {'opponent': 'Team D', 'opp_def_rank': 25, 'yards_gained': 380},
]

Tasks: 1. Calculate raw average yards 2. Create a simple adjustment based on opponent rank 3. Which games were most impressive relative to opponent?


Exercise 3.4: Statistical Leaderboard

Create a leaderboard function:

players = [
    {'name': 'Player A', 'team': 'Alabama', 'rushing_yards': 1256, 'games': 13},
    {'name': 'Player B', 'team': 'Georgia', 'rushing_yards': 1189, 'games': 14},
    {'name': 'Player C', 'team': 'Michigan', 'rushing_yards': 1345, 'games': 15},
    {'name': 'Player D', 'team': 'Texas', 'rushing_yards': 1123, 'games': 13},
    {'name': 'Player E', 'team': 'Ohio State', 'rushing_yards': 1087, 'games': 12},
]

def create_leaderboard(players: list, stat: str,
                        per_game: bool = False,
                        top_n: int = 5) -> pd.DataFrame:
    """
    Create a leaderboard for a given statistic.

    Parameters:
    - stat: Which statistic to rank by
    - per_game: Whether to use per-game average
    - top_n: Number of players to include
    """
    pass  # Implement this

Exercise 3.5: Complete Team Profile

Build a comprehensive team statistics profile:

def create_team_profile(plays: pd.DataFrame, team: str) -> dict:
    """
    Generate complete team statistical profile.

    Returns dictionary with:
    - Offensive statistics (passing, rushing, total)
    - Defensive statistics
    - Special teams
    - Situational stats (3rd down, red zone)
    - Turnover margin
    """
    pass  # Implement this

Level 4: Advanced (Exercises 4.1-4.4)

Exercise 4.1: Historical Comparison Tool

Build a tool to compare players across eras:

class HistoricalComparison:
    """
    Compare players across different eras using era-adjusted statistics.
    """

    def __init__(self, league_averages: dict):
        """
        league_averages: {year: {stat: average}}
        """
        self.league_averages = league_averages

    def era_adjust(self, value: float, stat: str, year: int) -> float:
        """Adjust a statistic relative to era average."""
        pass

    def compare_players(self, player1: dict, player2: dict) -> pd.DataFrame:
        """
        Compare two players from potentially different eras.

        player dict: {name, year, stats: {stat: value}}
        """
        pass

Exercise 4.2: Play-by-Play Statistics Engine

Build a complete statistics engine from play-by-play data:

class PlayByPlayStats:
    """
    Calculate all traditional statistics from play-by-play data.
    """

    def __init__(self, plays: pd.DataFrame):
        self.plays = plays

    def passing_stats(self, team: str = None, player: str = None) -> pd.DataFrame:
        pass

    def rushing_stats(self, team: str = None, player: str = None) -> pd.DataFrame:
        pass

    def receiving_stats(self, team: str = None, player: str = None) -> pd.DataFrame:
        pass

    def team_summary(self, team: str) -> dict:
        pass

    def game_summary(self, game_id: int) -> dict:
        pass

    def season_leaders(self, stat: str, position: str = None) -> pd.DataFrame:
        pass

Exercise 4.3: Box Score Generator

Create a function that generates a formatted box score from play-by-play data:

def generate_box_score(plays: pd.DataFrame, game_id: int) -> str:
    """
    Generate a formatted box score string from play-by-play data.

    Should include:
    - Score by quarter
    - Team statistics comparison
    - Individual leaders (passing, rushing, receiving)
    - Key plays summary
    """
    pass  # Implement this

Exercise 4.4: Statistical Report Generator

Create a complete statistical report for a team's season:

class SeasonReport:
    """
    Generate comprehensive season statistical report.
    """

    def __init__(self, team: str, season: int, plays: pd.DataFrame):
        self.team = team
        self.season = season
        self.plays = plays

    def offensive_summary(self) -> dict:
        """Season offensive statistics."""
        pass

    def defensive_summary(self) -> dict:
        """Season defensive statistics."""
        pass

    def game_by_game(self) -> pd.DataFrame:
        """Game-by-game breakdown."""
        pass

    def player_statistics(self) -> dict:
        """Individual player statistics."""
        pass

    def generate_report(self) -> str:
        """Generate formatted text report."""
        pass

Level 5: Mastery (Exercises 5.1-5.2)

Exercise 5.1: Complete Statistics Package

Build a production-ready statistics package:

class FootballStatistics:
    """
    Complete football statistics package.

    Features:
    - Calculate all traditional statistics
    - Support team and player levels
    - Game, season, and career aggregations
    - Leaderboards and rankings
    - Formatted output (box scores, reports)
    - Data validation
    """

    def __init__(self, data_source):
        pass

    # Implement all methods needed for a complete package

Exercise 5.2: Statistics API

Create a REST API-like interface for statistics:

class StatsAPI:
    """
    API-like interface for accessing football statistics.

    Endpoints:
    - get_player_stats(player_id, season, stat_type)
    - get_team_stats(team, season, stat_type)
    - get_game_stats(game_id)
    - get_leaderboard(stat, season, limit)
    - compare_players(player_ids, stats)
    - compare_teams(team_ids, stats)
    """

    def __init__(self, database):
        pass

    # Implement endpoint methods

Submission Guidelines

For each exercise:

  1. Code: Well-documented, following PEP 8
  2. Output: Show results of running your code
  3. Interpretation: Explain what the statistics mean
  4. Validation: Verify calculations are correct

Example format:

# Exercise X.Y: Title

def my_solution(data):
    """Calculate the required statistics."""
    # Implementation
    pass

# Test
result = my_solution(test_data)
print(f"Result: {result}")

# Interpretation
# The completion percentage of 65.2% is above the FBS average of ~62%,
# indicating above-average accuracy for this quarterback.