Code Examples

Copy-paste ready R and Python code for NFL analytics. From data loading to machine learning models.

122 Examples
R & Python Support: All examples include both R and Python versions. Click the tabs to switch between languages. Use the copy button to copy code to clipboard.

Defensive Analytics

Analyze defensive performance, coverage, and pressure metrics

Defensive EPA by Unit
Rank defenses by EPA allowed per play.
Intermediate
library(nflfastR)
library(tidyverse)

pbp <- load_pbp(2023)

# Defensive EPA rankings
def_epa <- pbp %>%
  filter(!is.na(epa), play_type %in% c("pass", "run")) %>%
  group_by(defteam) %>%
  summarize(
    plays = n(),
    epa_allowed = mean(epa),
    pass_epa_allowed = mean(epa[play_type == "pass"]),
    rush_epa_allowed = mean(epa[play_type == "run"]),
    success_allowed = mean(success) * 100,
    .groups = "drop"
  ) %>%
  arrange(epa_allowed)  # Lower is better

print(def_epa)
import nfl_data_py as nfl
import pandas as pd

pbp = nfl.import_pbp_data([2023])

# Defensive EPA rankings
plays = pbp[(pbp["epa"].notna()) & (pbp["play_type"].isin(["pass", "run"]))]

def_epa = (plays.groupby("defteam")
    .agg(
        plays=("epa", "count"),
        epa_allowed=("epa", "mean"),
        success_allowed=("success", lambda x: x.mean() * 100)
    )
    .reset_index()
    .sort_values("epa_allowed"))  # Lower is better

print("Defensive EPA Rankings (lower is better):")
print(def_epa)
Packages: nflfastR tidyverse nfl_data_py pandas
Pass Rush Metrics
Analyze pass rush effectiveness and sack rates.
Intermediate
library(nflfastR)
library(tidyverse)

pbp <- load_pbp(2023)

# Team pass rush metrics
pass_rush <- pbp %>%
  filter(play_type == "pass", !is.na(epa)) %>%
  group_by(defteam) %>%
  summarize(
    pass_plays_faced = n(),
    sacks = sum(sack),
    sack_rate = mean(sack) * 100,
    qb_hits = sum(qb_hit, na.rm = TRUE),
    epa_allowed = mean(epa),
    .groups = "drop"
  ) %>%
  arrange(desc(sack_rate))

print(pass_rush)
import nfl_data_py as nfl
import pandas as pd

pbp = nfl.import_pbp_data([2023])

# Pass rush metrics
pass_plays = pbp[(pbp["play_type"] == "pass") & (pbp["epa"].notna())]

pass_rush = (pass_plays.groupby("defteam")
    .agg(
        pass_plays=("epa", "count"),
        sacks=("sack", "sum"),
        sack_rate=("sack", lambda x: x.mean() * 100),
        epa_allowed=("epa", "mean")
    )
    .reset_index()
    .sort_values("sack_rate", ascending=False))

print("Team Pass Rush Effectiveness:")
print(pass_rush)
Packages: nflfastR tidyverse nfl_data_py pandas
Red Zone Defense
Analyze defensive efficiency in the red zone.
Intermediate
library(nflfastR)
library(tidyverse)

pbp <- load_pbp(2023)

# Red zone defense
rz_defense <- pbp %>%
  filter(yardline_100 <= 20, !is.na(epa)) %>%
  group_by(defteam) %>%
  summarize(
    rz_plays = n(),
    rz_epa_allowed = mean(epa),
    td_allowed_rate = mean(touchdown, na.rm = TRUE) * 100,
    success_allowed = mean(success) * 100,
    .groups = "drop"
  ) %>%
  arrange(rz_epa_allowed)

print(rz_defense)
import nfl_data_py as nfl
import pandas as pd

pbp = nfl.import_pbp_data([2023])

# Red zone defense
rz_plays = pbp[(pbp["yardline_100"] <= 20) & (pbp["epa"].notna())]

rz_defense = (rz_plays.groupby("defteam")
    .agg(
        rz_plays=("epa", "count"),
        rz_epa_allowed=("epa", "mean"),
        td_allowed_rate=("touchdown", lambda x: x.mean() * 100)
    )
    .reset_index()
    .sort_values("rz_epa_allowed"))

print("Red Zone Defense Rankings:")
print(rz_defense)
Packages: nflfastR tidyverse nfl_data_py pandas
Third Down Defense
Analyze defensive third down conversion rate allowed.
Intermediate
library(nflfastR)
library(tidyverse)

pbp <- load_pbp(2023)

# Third down defense
third_down_def <- pbp %>%
  filter(down == 3, !is.na(epa)) %>%
  group_by(defteam) %>%
  summarize(
    third_downs = n(),
    conversions_allowed = sum(first_down, na.rm = TRUE),
    conv_rate_allowed = mean(first_down, na.rm = TRUE) * 100,
    epa_allowed = mean(epa),
    .groups = "drop"
  ) %>%
  arrange(conv_rate_allowed)

print(third_down_def)
import nfl_data_py as nfl
import pandas as pd

pbp = nfl.import_pbp_data([2023])

# Third down defense
third_down = pbp[(pbp["down"] == 3) & (pbp["epa"].notna())]

third_down_def = (third_down.groupby("defteam")
    .agg(
        third_downs=("epa", "count"),
        conv_rate_allowed=("first_down", lambda x: x.mean() * 100),
        epa_allowed=("epa", "mean")
    )
    .reset_index()
    .sort_values("conv_rate_allowed"))

print("Third Down Defense (lower is better):")
print(third_down_def)
Packages: nflfastR tidyverse nfl_data_py pandas
Turnover Creation Rate
Analyze which defenses create the most turnovers.
Intermediate
library(nflfastR)
library(tidyverse)

pbp <- load_pbp(2023)

# Turnover analysis by defense
turnovers <- pbp %>%
  filter(!is.na(defteam)) %>%
  group_by(defteam) %>%
  summarize(
    plays = n(),
    interceptions = sum(interception, na.rm = TRUE),
    fumbles_forced = sum(fumble_lost, na.rm = TRUE),
    total_turnovers = interceptions + fumbles_forced,
    turnover_rate = total_turnovers / plays * 100,
    .groups = "drop"
  ) %>%
  arrange(desc(total_turnovers))

print(turnovers)
import nfl_data_py as nfl
import pandas as pd

pbp = nfl.import_pbp_data([2023])

# Turnover analysis
plays = pbp[pbp["defteam"].notna()]

turnovers = (plays.groupby("defteam")
    .agg(
        plays=("epa", "count"),
        interceptions=("interception", "sum"),
        fumbles=("fumble_lost", "sum")
    )
    .reset_index())

turnovers["total_turnovers"] = turnovers["interceptions"] + turnovers["fumbles"]
turnovers["turnover_rate"] = turnovers["total_turnovers"] / turnovers["plays"] * 100
turnovers = turnovers.sort_values("total_turnovers", ascending=False)

print("Defensive Turnovers Created:")
print(turnovers)
Packages: nflfastR tidyverse nfl_data_py pandas
Yards After Catch Allowed
Analyze defensive ability to limit yards after catch.
Intermediate
library(nflfastR)
library(tidyverse)

pbp <- load_pbp(2023)

# YAC allowed analysis
yac_allowed <- pbp %>%
  filter(complete_pass == 1, !is.na(yards_after_catch)) %>%
  group_by(defteam) %>%
  summarize(
    completions_allowed = n(),
    total_yac_allowed = sum(yards_after_catch),
    avg_yac_allowed = mean(yards_after_catch),
    .groups = "drop"
  ) %>%
  arrange(avg_yac_allowed)

print(yac_allowed)
import nfl_data_py as nfl
import pandas as pd

pbp = nfl.import_pbp_data([2023])

# YAC allowed
completions = pbp[(pbp["complete_pass"] == 1) & (pbp["yards_after_catch"].notna())]

yac_allowed = (completions.groupby("defteam")
    .agg(
        completions=("yards_after_catch", "count"),
        total_yac=("yards_after_catch", "sum"),
        avg_yac=("yards_after_catch", "mean")
    )
    .reset_index()
    .sort_values("avg_yac"))

print("YAC Allowed by Defense (lower is better):")
print(yac_allowed)
Packages: nflfastR tidyverse nfl_data_py pandas
Quick Package Reference
R Packages
  • nflfastR - Play-by-play data with EPA
  • nflplotR - NFL team logos & plotting
  • tidyverse - Data manipulation & visualization
  • ggplot2 - Advanced visualizations
Python Packages
  • nfl_data_py - NFL data (nflverse compatible)
  • pandas - Data manipulation
  • matplotlib - Visualizations
  • scikit-learn - Machine learning

Ready to Dive Deeper?

Learn the theory behind these techniques in our comprehensive tutorial series

Browse Tutorials