Copy-paste ready R and Python code for NFL analytics. From data loading to machine learning models.
Analyze kicking, punting, and return game performance
library(nflfastR)
library(tidyverse)
pbp <- load_pbp(2023)
# Field goal analysis
fg_analysis <- pbp %>%
filter(play_type == "field_goal", !is.na(kick_distance)) %>%
mutate(
distance_bucket = case_when(
kick_distance < 30 ~ "Under 30",
kick_distance < 40 ~ "30-39",
kick_distance < 50 ~ "40-49",
TRUE ~ "50+"
)
) %>%
group_by(distance_bucket) %>%
summarize(
attempts = n(),
makes = sum(field_goal_result == "made"),
pct = mean(field_goal_result == "made") * 100,
.groups = "drop"
)
print(fg_analysis)
# Team kicking rankings
team_fg <- pbp %>%
filter(play_type == "field_goal") %>%
group_by(posteam) %>%
summarize(
attempts = n(),
makes = sum(field_goal_result == "made"),
pct = mean(field_goal_result == "made") * 100,
avg_distance = mean(kick_distance, na.rm = TRUE)
) %>%
arrange(desc(pct))
print(team_fg)
import nfl_data_py as nfl
import pandas as pd
pbp = nfl.import_pbp_data([2023])
# Field goal analysis
fgs = pbp[(pbp["play_type"] == "field_goal") & (pbp["kick_distance"].notna())]
def distance_bucket(d):
if d < 30: return "Under 30"
elif d < 40: return "30-39"
elif d < 50: return "40-49"
else: return "50+"
fgs["distance_bucket"] = fgs["kick_distance"].apply(distance_bucket)
fg_analysis = (fgs.groupby("distance_bucket")
.agg(
attempts=("field_goal_result", "count"),
makes=("field_goal_result", lambda x: (x == "made").sum()),
pct=("field_goal_result", lambda x: (x == "made").mean() * 100)
)
.reset_index())
print("Field Goal Accuracy by Distance:")
print(fg_analysis)
nflfastR
tidyverse
nfl_data_py
pandas
library(nflfastR)
library(tidyverse)
pbp <- load_pbp(2023)
# Punter analysis
punt_analysis <- pbp %>%
filter(play_type == "punt", !is.na(kick_distance)) %>%
group_by(punter_player_name) %>%
summarize(
punts = n(),
avg_gross = mean(kick_distance),
inside_20 = sum(yardline_100 <= 20, na.rm = TRUE),
touchbacks = sum(touchback, na.rm = TRUE),
.groups = "drop"
) %>%
filter(punts >= 20) %>%
arrange(desc(avg_gross))
print(punt_analysis)
import nfl_data_py as nfl
import pandas as pd
pbp = nfl.import_pbp_data([2023])
# Punt analysis
punts = pbp[(pbp["play_type"] == "punt") & (pbp["kick_distance"].notna())]
punt_analysis = (punts.groupby("punter_player_name")
.agg(
punts=("kick_distance", "count"),
avg_gross=("kick_distance", "mean"),
touchbacks=("touchback", "sum")
)
.reset_index())
punt_analysis = punt_analysis[punt_analysis["punts"] >= 20].sort_values(
"avg_gross", ascending=False)
print("Punter Rankings:")
print(punt_analysis)
nflfastR
tidyverse
nfl_data_py
pandas
library(nflfastR)
library(tidyverse)
pbp <- load_pbp(2023)
# Kickoff return analysis
ko_returns <- pbp %>%
filter(play_type == "kickoff", !is.na(return_yards)) %>%
group_by(posteam) %>%
summarize(
returns = n(),
total_yards = sum(return_yards),
avg_return = mean(return_yards),
touchbacks = sum(touchback, na.rm = TRUE),
return_tds = sum(return_touchdown, na.rm = TRUE),
.groups = "drop"
) %>%
arrange(desc(avg_return))
print(ko_returns)
import nfl_data_py as nfl
import pandas as pd
pbp = nfl.import_pbp_data([2023])
# Kickoff return analysis
kickoffs = pbp[(pbp["play_type"] == "kickoff") & (pbp["return_yards"].notna())]
ko_returns = (kickoffs.groupby("posteam")
.agg(
returns=("return_yards", "count"),
total_yards=("return_yards", "sum"),
avg_return=("return_yards", "mean"),
tds=("return_touchdown", "sum")
)
.reset_index()
.sort_values("avg_return", ascending=False))
print("Kickoff Return Rankings:")
print(ko_returns)
nflfastR
tidyverse
nfl_data_py
pandas
library(nflfastR)
library(tidyverse)
pbp <- load_pbp(2023)
# Punt return analysis
punt_returns <- pbp %>%
filter(play_type == "punt", !is.na(return_yards), return_yards > 0) %>%
group_by(posteam) %>%
summarize(
returns = n(),
total_yards = sum(return_yards),
avg_return = mean(return_yards),
return_tds = sum(return_touchdown, na.rm = TRUE),
.groups = "drop"
) %>%
arrange(desc(avg_return))
print(punt_returns)
import nfl_data_py as nfl
import pandas as pd
pbp = nfl.import_pbp_data([2023])
# Punt return analysis
punt_returns = pbp[(pbp["play_type"] == "punt") &
(pbp["return_yards"].notna()) &
(pbp["return_yards"] > 0)]
pr_analysis = (punt_returns.groupby("posteam")
.agg(
returns=("return_yards", "count"),
total_yards=("return_yards", "sum"),
avg_return=("return_yards", "mean")
)
.reset_index()
.sort_values("avg_return", ascending=False))
print("Punt Return Rankings:")
print(pr_analysis)
nflfastR
tidyverse
nfl_data_py
pandas
library(nflfastR)
library(tidyverse)
pbp <- load_pbp(2023)
# Special teams EPA by play type
st_epa <- pbp %>%
filter(special_teams_play == 1, !is.na(epa)) %>%
mutate(
st_play_type = case_when(
play_type == "kickoff" ~ "Kickoff",
play_type == "punt" ~ "Punt",
play_type == "field_goal" ~ "Field Goal",
play_type == "extra_point" ~ "Extra Point",
TRUE ~ "Other"
)
) %>%
group_by(posteam, st_play_type) %>%
summarize(
plays = n(),
total_epa = sum(epa),
avg_epa = mean(epa),
.groups = "drop"
)
# Team special teams rankings
team_st_epa <- pbp %>%
filter(special_teams_play == 1, !is.na(epa)) %>%
group_by(posteam) %>%
summarize(
total_st_epa = sum(epa),
avg_st_epa = mean(epa),
st_plays = n()
) %>%
arrange(desc(total_st_epa))
print(team_st_epa)
import nfl_data_py as nfl
import pandas as pd
pbp = nfl.import_pbp_data([2023])
# Filter special teams plays
st_plays = pbp[(pbp["special_teams_play"] == 1) & (pbp["epa"].notna())]
# Map play types
def st_type(play):
if play == "kickoff": return "Kickoff"
elif play == "punt": return "Punt"
elif play == "field_goal": return "Field Goal"
elif play == "extra_point": return "Extra Point"
else: return "Other"
st_plays["st_play_type"] = st_plays["play_type"].apply(st_type)
# Team special teams EPA
team_st_epa = (st_plays.groupby("posteam")
.agg(
total_st_epa=("epa", "sum"),
avg_st_epa=("epa", "mean"),
st_plays=("epa", "count")
)
.reset_index()
.sort_values("total_st_epa", ascending=False))
print("Special Teams EPA Rankings:")
print(team_st_epa)
nflfastR
tidyverse
nfl_data_py
pandas
library(nflfastR)
library(tidyverse)
pbp <- load_pbp(2020:2023)
# Find blocked kicks
blocked_kicks <- pbp %>%
filter(
play_type %in% c("field_goal", "punt", "extra_point"),
str_detect(tolower(desc), "block")
) %>%
mutate(
blocked_type = play_type
)
# Blocked kicks by team (blocking team)
team_blocks <- blocked_kicks %>%
group_by(defteam, blocked_type) %>%
summarize(blocks = n(), .groups = "drop") %>%
pivot_wider(names_from = blocked_type, values_from = blocks, values_fill = 0) %>%
mutate(total_blocks = rowSums(across(where(is.numeric)))) %>%
arrange(desc(total_blocks))
print("Teams with Most Blocked Kicks (2020-2023):")
print(team_blocks)
# Blocked kicks allowed
blocks_allowed <- blocked_kicks %>%
group_by(posteam, blocked_type) %>%
summarize(blocked = n(), .groups = "drop") %>%
pivot_wider(names_from = blocked_type, values_from = blocked, values_fill = 0) %>%
mutate(total_blocked = rowSums(across(where(is.numeric)))) %>%
arrange(desc(total_blocked))
print("\nTeams with Most Kicks Blocked Against:")
print(blocks_allowed)
import nfl_data_py as nfl
import pandas as pd
pbp = nfl.import_pbp_data([2020, 2021, 2022, 2023])
# Find blocked kicks
st_plays = pbp[pbp["play_type"].isin(["field_goal", "punt", "extra_point"])]
blocked = st_plays[st_plays["desc"].str.lower().str.contains("block", na=False)]
# Blocked kicks by blocking team
team_blocks = (blocked.groupby(["defteam", "play_type"])
.size()
.reset_index(name="blocks"))
# Pivot to get blocks by type
blocks_pivot = team_blocks.pivot_table(
index="defteam",
columns="play_type",
values="blocks",
fill_value=0
).reset_index()
blocks_pivot["total_blocks"] = blocks_pivot.select_dtypes(include="number").sum(axis=1)
blocks_pivot = blocks_pivot.sort_values("total_blocks", ascending=False)
print("Teams with Most Blocked Kicks (2020-2023):")
print(blocks_pivot.head(10))
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