Analysing NFL Team Performance with Python: Using Standings Data for Insights

You want data that tells a story.

NFL statistics hold a lot of narratives waiting to be seen – from a quarterback’s career-defining season to a defence’s gradual improvement.

And we’ll find these stories with Python.

Every football season generates mountains of raw data. You need the right tools to make sense of it all. Through Python, you’ll learn to process team standings, parse play-by-play data, and create visualizations that reveal patterns human eyes might miss.

Your analysis can answer questions like:

  • Which teams perform best in close games?
  • Do certain coaching decisions correlate with winning?
  • What statistical factors predict playoff success?

The skills we’ll learn here are not just for NFL standings and NFL-related data analysis.

It will also help you with data cleaning, statistical analysis, and visualization techniques apply to any field where numbers tell a story.

Let’s get started.

Read: NumPy and Linear Regression: Efficient Python Techniques for Large Datasets

Step 1: Set up your environment

First, we’ll need to install the required packages. The nfl_data_py package provides easy access to NFL statistics, while pandas and plotly will handle our data manipulation and visualization needs.

pip install nfl_data_py pandas plotly numpy seaborn matplotlib

Let’s import our required libraries and set up the basic environment:

# Step 1: Import necessary libraries
import pandas as pd
import nfl_data_py as nfl
import plotly.graph_objects as go
import seaborn as sns
import matplotlib.pyplot as plt
import numpy as np
from datetime import datetime

Also read: [Fix] ImportError: cannot import name ‘get_config’ from ‘tensorflow.python.eager.context’

Step 2: Collecting and prepare data for analysis

We’ll start by importing team descriptions and weekly player data. Then, we’ll ensure we have team details merged properly by using recent_team and team_abbr.

# Step 2: Collect and Prepare Data
teams_df = nfl.import_team_desc()
weekly_data = nfl.import_weekly_data([2024])

# Display columns in weekly_data and teams_df
print("Columns in weekly_data:", weekly_data.columns)
print("Columns in teams_df:", teams_df.columns)

# Merge data on 'recent_team' in weekly_data and 'team_abbr' in teams_df
weekly_data = weekly_data.merge(
    teams_df[['team_abbr', 'team_name']], 
    left_on='recent_team', 
    right_on='team_abbr', 
    how='left'
)
print("Sample of Merged Data:\n", weekly_data.head())  # Confirm merge output# Step 2: Collect and Prepare Data
teams_df = nfl.import_team_desc()
weekly_data = nfl.import_weekly_data([2024])

# Display columns in weekly_data and teams_df
print("Columns in weekly_data:", weekly_data.columns)
print("Columns in teams_df:", teams_df.columns)

# Merge data on 'recent_team' in weekly_data and 'team_abbr' in teams_df
weekly_data = weekly_data.merge(
    teams_df[['team_abbr', 'team_name']], 
    left_on='recent_team', 
    right_on='team_abbr', 
    how='left'
)
print("Sample of Merged Data:\n", weekly_data.head())  # Confirm merge output
Merged data sample

Step 3: Calculate performance metrics

The weekly_data set doesn’t include direct team wins or losses, so we’ll calculate alternative metrics based on available data.

I’ll start by aggregating passing_yards, rushing_yards, and total points (fantasy_points) per team to get an idea of each team’s offensive strength.

# Step 3: Calculate Offensive Metrics
def calculate_offensive_metrics(df):
    metrics = df.groupby('team_name').agg({
        'passing_yards': 'sum',
        'rushing_yards': 'sum',
        'fantasy_points': 'sum'
    }).reset_index()
    
    metrics['total_yards'] = metrics['passing_yards'] + metrics['rushing_yards']
    return metrics

# Calculate and display offensive metrics
offensive_metrics = calculate_offensive_metrics(weekly_data)
print("\nOffensive Metrics:\n", offensive_metrics)
Offensive metrics NFL Standings

Step 4: Visualize offensive performance

Now let’s put this data into some sort of a visual with the plotly library. We’ll use bar charts to show total yards and fantasy points as proxies for offensive power.

# Step 4: Visualize Offensive Performance
def plot_total_yards(metrics_df):
    plt.figure(figsize=(12, 6))
    sns.barplot(data=metrics_df.sort_values('total_yards', ascending=False),
                x='team_name', y='total_yards')
    plt.xticks(rotation=45, ha='right')
    plt.title('Total Yards by Team')
    plt.tight_layout()
    plt.show()

def plot_fantasy_points(metrics_df):
    plt.figure(figsize=(12, 6))
    sns.barplot(data=metrics_df.sort_values('fantasy_points', ascending=False),
                x='team_name', y='fantasy_points')
    plt.xticks(rotation=45, ha='right')
    plt.title('Fantasy Points by Team')
    plt.tight_layout()
    plt.show()

# Generate visualizations
plot_total_yards(offensive_metrics)
plot_fantasy_points(offensive_metrics)
Bar chart for total yards by team

If you close this chart, you’ll see the next chart plotting fantasy points by team.

Fantasy points by team bar chart

These charts highlight which teams are leading in offensive output, using total yards and fantasy points as indicators.

Step 5: Calculate efficiency ratings

Awesome! Next, we’ll focus on average passing_yards and rushing_yards per game to estimate efficiency, with league averages as a baseline.

# Step 5: Calculate Efficiency Ratings
def calculate_efficiency(df):
    efficiency = df.groupby('team_name').agg({
        'passing_yards': 'mean',
        'rushing_yards': 'mean'
    }).reset_index()
    
    league_avg_passing = efficiency['passing_yards'].mean()
    league_avg_rushing = efficiency['rushing_yards'].mean()
    
    efficiency['passing_efficiency'] = (efficiency['passing_yards'] / league_avg_passing) * 100
    efficiency['rushing_efficiency'] = (efficiency['rushing_yards'] / league_avg_rushing) * 100
    
    return efficiency

# Calculate and display efficiency ratings
efficiency_metrics = calculate_efficiency(weekly_data)
print("\nEfficiency Metrics:\n", efficiency_metrics)
Plotting efficiency metrics

Step 6: Build a team dashboard

A dashboard provides a summarized view of team performance using calculated metrics like total yards, fantasy points, and efficiency ratings.

# Step 6: Build a Team Dashboard
def create_team_dashboard(team_name, offensive_df, efficiency_df):
    team_offense = offensive_df[offensive_df['team_name'] == team_name].iloc[0]
    team_efficiency = efficiency_df[efficiency_df['team_name'] == team_name].iloc[0]
    
    print(f"\nPerformance Dashboard for {team_name}")
    print("-" * 50)
    print(f"Total Passing Yards: {team_offense['passing_yards']}")
    print(f"Total Rushing Yards: {team_offense['rushing_yards']}")
    print(f"Total Fantasy Points: {team_offense['fantasy_points']}")
    print(f"Passing Efficiency: {team_efficiency['passing_efficiency']:.1f}")
    print(f"Rushing Efficiency: {team_efficiency['rushing_efficiency']:.1f}")

# Example usage for a specific team
create_team_dashboard("New York Jets", offensive_metrics, efficiency_metrics)

Performance of New York Jets

Step 7: Analyze trends over time

To track weekly scoring trends, plot data for each team to see changes in passing and rushing yards over time.

# Step 7: Analyze Trends Over Time
def analyze_team_trends(df, team_name):
    team_data = df[df['team_name'] == team_name].sort_values('week').copy()
    
    # Replace zeros with NaN and fill using forward fill (to keep actual zeroes, skip this step)
    team_data['passing_yards'].replace(0, np.nan, inplace=True)
    team_data['rushing_yards'].replace(0, np.nan, inplace=True)
    team_data['passing_yards'].fillna(method='ffill', inplace=True)
    team_data['rushing_yards'].fillna(method='ffill', inplace=True)

    # Optional: Calculate rolling averages to smoothen trends
    team_data['passing_yards_avg'] = team_data['passing_yards'].rolling(window=3, min_periods=1).mean()
    team_data['rushing_yards_avg'] = team_data['rushing_yards'].rolling(window=3, min_periods=1).mean()

    # Plot passing and rushing yards over weeks with smoothing
    plt.figure(figsize=(12, 6))
    plt.plot(team_data['week'], team_data['passing_yards_avg'], label='Passing Yards (3-week avg)', color='blue')
    plt.plot(team_data['week'], team_data['rushing_yards_avg'], label='Rushing Yards (3-week avg)', color='orange')
    plt.title(f'{team_name} Yards Over Time (Smoothed)')
    plt.xlabel('Week')
    plt.ylabel('Yards')
    plt.legend()
    plt.grid(True)
    plt.tight_layout()
    plt.show()

# Example trend analysis with improved visualization for New York Jets
analyze_team_trends(weekly_data, "New York Jets")

Plotting yards over time.

Step 8: Predict future performance

Using a rolling average on weekly data for each team, this simple function estimates passing and rushing yards in the next game.

Predicting next game performance

Wrap up

You’ve now created a detailed analysis framework for NFL team performance using Python. You can track team success with win percentages, compare offensive and defensive efficiency, observe weekly trends, and even forecast future outcomes.

Hope this short guide helped you understand a fair bit of data analysis!

Ninad Pathak
Ninad Pathak

Ninad is a Python and PHP developer turned writer out of passion. Over the last 6+ years, he has written for brands including DigitalOcean, DreamHost, Hostinger, and many others. When not working, you'll find him tinkering with open-source projects, vibe coding, or on a mountain trail, completely disconnected from tech.

Articles: 39