Copy-paste ready R and Python code for NFL analytics. From data loading to machine learning models.
Analyze defensive performance, coverage, and pressure metrics
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)
nflfastR
tidyverse
nfl_data_py
pandas
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)
nflfastR
tidyverse
nfl_data_py
pandas
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)
nflfastR
tidyverse
nfl_data_py
pandas
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)
nflfastR
tidyverse
nfl_data_py
pandas
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)
nflfastR
tidyverse
nfl_data_py
pandas
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)
nflfastR
tidyverse
nfl_data_py
pandas
nflfastR - Play-by-play data with EPAnflplotR - NFL team logos & plottingtidyverse - Data manipulation & visualizationggplot2 - Advanced visualizationsnfl_data_py - NFL data (nflverse compatible)pandas - Data manipulationmatplotlib - Visualizationsscikit-learn - Machine learningLearn the theory behind these techniques in our comprehensive tutorial series
Browse Tutorials