#Libraries:
library(dplyr)
library(ggplot2)
library(nflfastR)
Let’s work a little bit with NFL data from the nflfastR package in CRAN.
We need to upload the available NFL Data.
#Uploading NFL Data:
#Play by Play Data:
= load_pbp(season = 2022)
data_pbp_2022 head(data_pbp_2022, 5)
# A tibble: 5 × 372
play_id game_id old_g…¹ home_…² away_…³ seaso…⁴ week posteam poste…⁵ defteam
<dbl> <chr> <chr> <chr> <chr> <chr> <int> <chr> <chr> <chr>
1 1 2022_01… 202209… NYJ BAL REG 1 <NA> <NA> <NA>
2 43 2022_01… 202209… NYJ BAL REG 1 NYJ home BAL
3 68 2022_01… 202209… NYJ BAL REG 1 NYJ home BAL
4 89 2022_01… 202209… NYJ BAL REG 1 NYJ home BAL
5 115 2022_01… 202209… NYJ BAL REG 1 NYJ home BAL
# … with 362 more variables: side_of_field <chr>, yardline_100 <dbl>,
# game_date <chr>, quarter_seconds_remaining <dbl>,
# half_seconds_remaining <dbl>, game_seconds_remaining <dbl>,
# game_half <chr>, quarter_end <dbl>, drive <dbl>, sp <dbl>, qtr <dbl>,
# down <dbl>, goal_to_go <dbl>, time <chr>, yrdln <chr>, ydstogo <dbl>,
# ydsnet <dbl>, desc <chr>, play_type <chr>, yards_gained <dbl>,
# shotgun <dbl>, no_huddle <dbl>, qb_dropback <dbl>, qb_kneel <dbl>, …
# ℹ Use `colnames()` to see all variable names
#Players Stats:
= load_player_stats(season = 2022)
data_players_stats head(data_players_stats, 5)
# A tibble: 5 × 52
player_id playe…¹ playe…² posit…³ posit…⁴ heads…⁵ recen…⁶ season week seaso…⁷
<chr> <chr> <chr> <chr> <chr> <chr> <chr> <int> <int> <chr>
1 00-00195… T.Brady Tom Br… QB QB https:… TB 2022 1 REG
2 00-00195… T.Brady Tom Br… QB QB https:… TB 2022 2 REG
3 00-00195… T.Brady Tom Br… QB QB https:… TB 2022 3 REG
4 00-00195… T.Brady Tom Br… QB QB https:… TB 2022 4 REG
5 00-00195… T.Brady Tom Br… QB QB https:… TB 2022 5 REG
# … with 42 more variables: completions <int>, attempts <int>,
# passing_yards <dbl>, passing_tds <int>, interceptions <dbl>, sacks <dbl>,
# sack_yards <dbl>, sack_fumbles <int>, sack_fumbles_lost <int>,
# passing_air_yards <dbl>, passing_yards_after_catch <dbl>,
# passing_first_downs <dbl>, passing_epa <dbl>,
# passing_2pt_conversions <int>, pacr <dbl>, dakota <dbl>, carries <int>,
# rushing_yards <dbl>, rushing_tds <int>, rushing_fumbles <dbl>, …
# ℹ Use `colnames()` to see all variable names
So, we got a lot of data available of the 2022 NFL Season, I loaded to dataframes into R from the package repository:
- data_pbp_2022 = play by play data from all 2022 NFL’s Games from all teams
- data_players_stats = players stats from all weeks
With this data we can look into some stuff that can help us understand what are the realy good teams and players, also I want to see if some of my favorites players are playing well and if they are corresponding my expectations.
After loading the data, since we got so many variables, especially in the play by play data, we need to see what are the columns that helps us out to reach our goal, so we can use the field descriptions available from the nflfastR to chose the columns we want.
#Fields Descriptions:
|>
field_descriptions mutate(print_string = paste(Field, Description, sep = ": ")) |>
select(Field, print_string)
# A tibble: 372 × 2
Field print_string
<chr> <chr>
1 play_id play_id: Numeric play id that when used with game_id and drive …
2 game_id game_id: Ten digit identifier for NFL game.
3 old_game_id old_game_id: Legacy NFL game ID.
4 home_team home_team: String abbreviation for the home team.
5 away_team away_team: String abbreviation for the away team.
6 season_type season_type: 'REG' or 'POST' indicating if the game belongs to …
7 week week: Season week.
8 posteam posteam: String abbreviation for the team with possession.
9 posteam_type posteam_type: String indicating whether the posteam team is hom…
10 defteam defteam: String abbreviation for the team on defense.
# … with 362 more rows
# ℹ Use `print(n = ...)` to see more rows
To chose the columns I want, I concatenated the field name and descriptions and clipped this to a simple sheet (Excel, LibreOffice, Google Sheets..) and started to check the columns I wanted, after I checked I the columns we just need to clip back to R and select only the fields we want.
#Selecting fields we want:
= data_pbp_2022 |>
data_pbp_2022_sel_fieds select(play_id,
game_id,
home_team,
away_team,
season_type,
week,
posteam,
defteam,
game_date,
drive,
sp,
qtr,
down,
yrdln,
desc,
play_type,
qb_dropback,
qb_scramble,
pass_length,
pass_location,
air_yards,
rushing_yards,
yards_after_catch,
td_team,
td_player_name,
posteam_score,
defteam_score,
penalty,
epa,
total_home_epa,
total_away_epa,
total_home_rush_epa,
total_away_rush_epa,
total_home_pass_epa,
total_away_pass_epa,
first_down_rush,
first_down_pass,
first_down_penalty,
third_down_converted,
third_down_failed,
fourth_down_converted,
fourth_down_failed,
away_score,
home_score,
location,
result,
spread_line,
passer_id )
So, from 372 available columns we selected 45 to beggin with. Now, we need to see the classes of this variables.
str(data_pbp_2022_sel_fieds)
nflverse_data [21,896 × 48] (S3: nflverse_data/tbl_df/tbl/data.table/data.frame)
$ play_id : num [1:21896] 1 43 68 89 115 136 172 202 230 254 ...
$ game_id : chr [1:21896] "2022_01_BAL_NYJ" "2022_01_BAL_NYJ" "2022_01_BAL_NYJ" "2022_01_BAL_NYJ" ...
$ home_team : chr [1:21896] "NYJ" "NYJ" "NYJ" "NYJ" ...
$ away_team : chr [1:21896] "BAL" "BAL" "BAL" "BAL" ...
$ season_type : chr [1:21896] "REG" "REG" "REG" "REG" ...
$ week : int [1:21896] 1 1 1 1 1 1 1 1 1 1 ...
$ posteam : chr [1:21896] NA "NYJ" "NYJ" "NYJ" ...
$ defteam : chr [1:21896] NA "BAL" "BAL" "BAL" ...
$ game_date : chr [1:21896] "2022-09-11" "2022-09-11" "2022-09-11" "2022-09-11" ...
$ drive : num [1:21896] NA 1 1 1 1 1 1 2 2 2 ...
$ sp : num [1:21896] 0 0 0 0 0 0 0 0 0 0 ...
$ qtr : num [1:21896] 1 1 1 1 1 1 1 1 1 1 ...
$ down : num [1:21896] NA NA 1 1 2 3 4 1 2 3 ...
$ yrdln : chr [1:21896] "BAL 35" "BAL 35" "NYJ 22" "NYJ 41" ...
$ desc : chr [1:21896] "GAME" "9-J.Tucker kicks 68 yards from BAL 35 to NYJ -3. 10-B.Berrios to NYJ 22 for 25 yards (51-J.Ross)." "(14:56) 32-Mi.Carter left end to NYJ 41 for 19 yards (32-M.Williams; 36-C.Clark)." "(14:29) (No Huddle, Shotgun) 19-J.Flacco pass incomplete short left to 32-Mi.Carter." ...
$ play_type : chr [1:21896] NA "kickoff" "run" "pass" ...
$ qb_dropback : num [1:21896] NA 0 0 1 0 1 0 1 1 0 ...
$ qb_scramble : num [1:21896] 0 0 0 0 0 0 0 0 0 0 ...
$ pass_length : chr [1:21896] NA NA NA "short" ...
$ pass_location : chr [1:21896] NA NA NA "left" ...
$ air_yards : num [1:21896] NA NA NA 0 NA 0 NA -4 3 NA ...
$ rushing_yards : num [1:21896] NA NA 19 NA 5 NA NA NA NA 4 ...
$ yards_after_catch : num [1:21896] NA NA NA NA NA NA NA 8 1 NA ...
$ td_team : chr [1:21896] NA NA NA NA ...
$ td_player_name : chr [1:21896] NA NA NA NA ...
$ posteam_score : num [1:21896] NA 0 0 0 0 0 0 0 0 0 ...
$ defteam_score : num [1:21896] NA 0 0 0 0 0 0 0 0 0 ...
$ penalty : num [1:21896] NA 0 0 0 0 1 0 0 0 0 ...
$ epa : num [1:21896] 0 -0.444 1.469 -0.492 -0.326 ...
$ total_home_epa : num [1:21896] 0 -0.444 1.025 0.533 0.207 ...
$ total_away_epa : num [1:21896] 0 0.444 -1.025 -0.533 -0.207 ...
$ total_home_rush_epa : num [1:21896] 0 0 1.47 1.47 1.14 ...
$ total_away_rush_epa : num [1:21896] 0 0 -1.47 -1.47 -1.14 ...
$ total_home_pass_epa : num [1:21896] 0 0 0 -0.492 -0.492 ...
$ total_away_pass_epa : num [1:21896] 0 0 0 0.492 0.492 ...
$ first_down_rush : num [1:21896] NA 0 1 0 0 0 0 0 0 1 ...
$ first_down_pass : num [1:21896] NA 0 0 0 0 0 0 0 0 0 ...
$ first_down_penalty : num [1:21896] NA 0 0 0 0 0 0 0 0 0 ...
$ third_down_converted : num [1:21896] NA 0 0 0 0 0 0 0 0 1 ...
$ third_down_failed : num [1:21896] NA 0 0 0 0 1 0 0 0 0 ...
$ fourth_down_converted: num [1:21896] NA 0 0 0 0 0 0 0 0 0 ...
$ fourth_down_failed : num [1:21896] NA 0 0 0 0 0 0 0 0 0 ...
$ away_score : int [1:21896] 24 24 24 24 24 24 24 24 24 24 ...
$ home_score : int [1:21896] 9 9 9 9 9 9 9 9 9 9 ...
$ location : chr [1:21896] "Home" "Home" "Home" "Home" ...
$ result : int [1:21896] -15 -15 -15 -15 -15 -15 -15 -15 -15 -15 ...
$ spread_line : num [1:21896] -6.5 -6.5 -6.5 -6.5 -6.5 -6.5 -6.5 -6.5 -6.5 -6.5 ...
$ passer_id : chr [1:21896] NA NA NA "00-0026158" ...
- attr(*, "nflverse_timestamp")= POSIXct[1:1], format: "2022-11-06 06:07:38"
- attr(*, "nflverse_type")= chr "play by play data"
- attr(*, "nflfastR_version")=Classes 'package_version', 'numeric_version' hidden list of 1
..$ : int [1:3] 4 5 0
Since we have play by play data, this dataset has a lot of NA values, because some columns only apply to specific plays, example, the air_yards variable will only have values when the play is a pass from the possession team.
Here, we need to create our dataframes using this available data, we don’t have a organized dataset with the teams statistics by week and etc, therefore, we need to do some cleaning and aggregation steps. But since we have offensive and defensive plays in the same datasets, we need to orient our data handling to the visuals we want to create, so lets work on it.
How are the Teams Tiers by Winning Pctg?
#Creating our wins dataframe by week:
= data_pbp_2022_sel_fieds |>
df_wins select(game_id, home_team, away_team, week, result) |> unique() |>
mutate(win = if_else(result <= 0, 0, 1)) #Creating a Win flag
#Adjusting to calculate all wins for all teams:
= rbind(#Home Teams Wins:
df_wins_adj |>
df_wins select(game_id, home_team, result, win) |>
rename(team_abbr = home_team),
#Away Teams Wins:
|>
df_wins select(game_id, away_team, result, win) |>
rename(team_abbr = away_team) |>
mutate(win = abs(win - 1))
)
#Plotting:
<- 1.618
asp_ratio
|>
df_wins_adj inner_join(select(teams_colors_logos, team_name, team_abbr, team_logo_espn), by = "team_abbr") |>
group_by(team_logo_espn, team_abbr, team_name) |>
summarise("Games Played" = n(),
"% Win" = sum(win)/n()) |>
##ggplot part:
ggplot(aes(x = reorder(team_name, -`% Win`), y = `% Win`)) +
geom_bar(stat = "identity", alpha = 0.8, col = "black") +
::geom_image(aes(image = team_logo_espn),
ggimagesize = 0.05, by = "width", asp = asp_ratio) +
scale_y_continuous(labels = scales::percent) +
theme_classic() +
theme(axis.text.x = element_blank(),
aspect.ratio = 1/asp_ratio) +
labs(x = "Teams", y = "Winning Percentage",
title = "Winning Percentage by Team Throught 8 Weeks")
Offensive and Defensive EPA
EPA is a very good measure for evaluating how good the teams units are playing.
#Off and Def EPA per Play:
|>
data_pbp_2022_sel_fieds select(game_id, play_id, posteam, defteam, week, epa) |>
na.omit() |>
::pivot_longer(c("posteam", "defteam"), names_to = "unit", values_to = "team_abbr") |>
tidyrmutate(unit = factor(unit, levels = c("posteam", "defteam"), labels = c("offense", "defense"))) |>
group_by(team_abbr, unit) |> summarise(avg_epa = mean(epa)) |> ungroup() |>
::spread(unit, avg_epa) |>
tidyrinner_join(select(teams_colors_logos, team_name, team_abbr, team_logo_espn), by = "team_abbr") |>
##ggplot aprt:
ggplot(aes(x = offense, y = defense)) +
geom_point(col = "white") +
::geom_image(aes(image = team_logo_espn),
ggimagesize = 0.05, by = "width", asp = asp_ratio) +
theme_classic() +
labs(x = "EPA/Play (Offense)",
y = "EPA/Play (Defense)",
title = "EPA by Team")
Play Selection Around the League
Here we got evaluate the play selection by each down and after we can look into it by each team.
#Plays Types in the dataset:
= data_pbp_2022_sel_fieds |>
df_plays filter(down %in% c(1, 2, 3) & penalty == 0) |>
select(game_id, posteam, play_type, down, week) |>
group_by(posteam, play_type) |> summarise(n = n()) |> mutate(freq = n/sum(n)) |>
select(-n) |> filter(play_type %in% c("run", "pass")) |>
arrange(play_type, desc(freq)) |> group_by(play_type) |>
mutate(id = if_else(play_type == "pass", row_number(), NULL)) |> ungroup() |>
group_by(posteam) |> mutate(id = sum(id, na.rm = T)) #This part is just to order the axis by the play type category
##ggplot part:
|>
df_plays ggplot(aes(x = reorder(posteam, id), y = freq, fill = play_type, label = round(freq*100, 0))) +
geom_bar(stat = "identity", col = "black") +
theme_classic() +
geom_text(position = position_stack(vjust = .5)) +
theme(axis.text.x = element_text(angle = 45, colour = "black"),
legend.position = "top") +
scale_y_continuous(labels = scales::percent) +
labs(x = "Team",
y = "Play Selection Percentage",
title = "Play Selection by Team",
subtitle = "Distribution of plays by each team ordered by the most pass centred offense to the least one on 3 Downs")
Air Yards versus Rush Yards per Play
|>
data_pbp_2022_sel_fieds select(game_id, play_id, posteam, air_yards, rushing_yards, play_type, penalty) |>
filter(!is.na(play_type) & play_type %in% c("run", "pass")) |>
group_by(posteam) |> summarise(avg_air = mean(air_yards, na.rm = T),
avg_rush = mean(rushing_yards, na.rm = T)) |>
rename(team_abbr = posteam) |>
inner_join(select(teams_colors_logos, team_name, team_abbr, team_logo_espn), by = "team_abbr") |>
ggplot(aes(x = avg_air, y = avg_rush)) +
geom_point(col = "white") +
::geom_image(aes(image = team_logo_espn),
ggimagesize = 0.05, by = "width", asp = asp_ratio) +
theme_classic() +
labs(x = "Air Yards per Play",
y = "Rush Yards per Play",
title = "Air Yards versus Rush Yards per Play by Team")
Play Selection and Field Position
For this one some manipulations have to be done.
`%!in%` = Negate(`%in%`)
= data_pbp_2022_sel_fieds |>
df_fields_plays_downs select(play_id, game_id, posteam, yrdln, play_type, down) |>
filter(!is.na(play_type) & play_type %!in% c("no_play", "kickoff", "extra_point") & !is.na(down)) |>
mutate(adj_play = forcats::fct_lump_n(play_type, n = 4, ties.method = "first", other_level = "Others Plays"), #Plays "Irrelevants" won't mather
field_position_num = if_else(stringr::word(yrdln, 1) == posteam, as.numeric(paste0("-", stringr::word(yrdln, 2))), as.numeric(stringr::word(yrdln, 2))),
field_position_cat = case_when(field_position_num <= -30 ~ "Own 20",
> -30 & field_position_num <= 0 ~ "Defensive Field > 20 Yrds",
field_position_num > 0 & field_position_num <= 30 ~ "Offensive Field - Not Red Zone",
field_position_num ~ "Red Zone"), #Creating categories for field position
T field_position_cat = factor(field_position_cat, levels = c("Own 20", "Defensive Field > 20 Yrds", "Offensive Field - Not Red Zone", "Red Zone")))
#Aggregation Part:
= df_fields_plays_downs |>
stats_fields_plays group_by(posteam, field_position_cat, adj_play) |>
summarise(n = n()) |> mutate(freq = n/sum(n)) |> select(-n) |>
::spread(adj_play, freq)
tidyris.na(stats_fields_plays)] = 0
stats_fields_plays[|> ungroup() |>
stats_fields_plays inner_join(select(teams_colors_logos, team_abbr, team_name), by = c("posteam" = "team_abbr")) |> select(-posteam) |>
select(team_name, field_position_cat, pass, run, field_goal, punt, `Others Plays`) |>
mutate_if(is.double, scales::percent, accuracy = 0.1) |>
::kable(align = "c") knitr
team_name | field_position_cat | pass | run | field_goal | punt | Others Plays |
---|---|---|---|---|---|---|
Arizona Cardinals | Own 20 | 60.6% | 30.6% | 0.0% | 8.8% | 0.0% |
Arizona Cardinals | Defensive Field > 20 Yrds | 64.0% | 27.4% | 0.0% | 7.9% | 0.6% |
Arizona Cardinals | Offensive Field - Not Red Zone | 50.3% | 39.5% | 7.5% | 0.0% | 2.7% |
Arizona Cardinals | Red Zone | 51.6% | 42.7% | 1.6% | 1.6% | 2.4% |
Atlanta Falcons | Own 20 | 40.0% | 49.0% | 0.0% | 11.0% | 0.0% |
Atlanta Falcons | Defensive Field > 20 Yrds | 43.3% | 45.3% | 0.0% | 7.3% | 4.0% |
Atlanta Falcons | Offensive Field - Not Red Zone | 33.1% | 56.2% | 9.9% | 0.0% | 0.8% |
Atlanta Falcons | Red Zone | 34.4% | 57.3% | 5.2% | 3.1% | 0.0% |
Baltimore Ravens | Own 20 | 47.4% | 40.8% | 0.0% | 9.9% | 2.0% |
Baltimore Ravens | Defensive Field > 20 Yrds | 57.1% | 34.9% | 0.0% | 5.6% | 2.4% |
Baltimore Ravens | Offensive Field - Not Red Zone | 44.0% | 47.8% | 8.2% | 0.0% | 0.0% |
Baltimore Ravens | Red Zone | 41.0% | 46.2% | 6.0% | 2.6% | 4.3% |
Buffalo Bills | Own 20 | 58.8% | 33.8% | 0.0% | 5.9% | 1.5% |
Buffalo Bills | Defensive Field > 20 Yrds | 64.8% | 29.5% | 0.0% | 2.3% | 3.4% |
Buffalo Bills | Offensive Field - Not Red Zone | 56.4% | 32.2% | 7.4% | 0.0% | 4.0% |
Buffalo Bills | Red Zone | 55.6% | 38.9% | 1.9% | 2.8% | 0.9% |
Carolina Panthers | Own 20 | 50.0% | 37.7% | 0.0% | 11.6% | 0.7% |
Carolina Panthers | Defensive Field > 20 Yrds | 55.1% | 33.5% | 0.0% | 10.8% | 0.6% |
Carolina Panthers | Offensive Field - Not Red Zone | 43.8% | 40.6% | 15.6% | 0.0% | 0.0% |
Carolina Panthers | Red Zone | 55.4% | 36.6% | 1.0% | 5.9% | 1.0% |
Chicago Bears | Own 20 | 43.0% | 50.8% | 0.0% | 6.2% | 0.0% |
Chicago Bears | Defensive Field > 20 Yrds | 38.0% | 50.9% | 0.0% | 11.0% | 0.0% |
Chicago Bears | Offensive Field - Not Red Zone | 30.6% | 56.0% | 9.0% | 0.0% | 4.5% |
Chicago Bears | Red Zone | 33.7% | 57.1% | 4.1% | 5.1% | 0.0% |
Cincinnati Bengals | Own 20 | 59.8% | 29.9% | 0.0% | 8.5% | 1.8% |
Cincinnati Bengals | Defensive Field > 20 Yrds | 59.4% | 29.7% | 0.0% | 7.8% | 3.1% |
Cincinnati Bengals | Offensive Field - Not Red Zone | 58.6% | 33.6% | 7.1% | 0.0% | 0.7% |
Cincinnati Bengals | Red Zone | 62.0% | 31.8% | 3.1% | 3.1% | 0.0% |
Cleveland Browns | Own 20 | 56.4% | 37.6% | 0.0% | 6.0% | 0.0% |
Cleveland Browns | Defensive Field > 20 Yrds | 51.1% | 41.5% | 0.0% | 6.7% | 0.7% |
Cleveland Browns | Offensive Field - Not Red Zone | 36.4% | 54.3% | 7.9% | 0.0% | 1.3% |
Cleveland Browns | Red Zone | 41.8% | 47.3% | 4.1% | 4.8% | 2.1% |
Dallas Cowboys | Own 20 | 54.3% | 33.3% | 0.0% | 8.5% | 3.9% |
Dallas Cowboys | Defensive Field > 20 Yrds | 42.9% | 46.9% | 0.0% | 9.7% | 0.6% |
Dallas Cowboys | Offensive Field - Not Red Zone | 38.6% | 48.5% | 10.9% | 0.0% | 2.0% |
Dallas Cowboys | Red Zone | 52.9% | 33.9% | 5.0% | 5.8% | 2.5% |
Denver Broncos | Own 20 | 51.4% | 35.2% | 0.0% | 13.4% | 0.0% |
Denver Broncos | Defensive Field > 20 Yrds | 52.9% | 37.8% | 0.0% | 8.1% | 1.2% |
Denver Broncos | Offensive Field - Not Red Zone | 52.8% | 31.5% | 12.0% | 0.0% | 3.7% |
Denver Broncos | Red Zone | 50.0% | 37.7% | 5.3% | 6.1% | 0.9% |
Detroit Lions | Own 20 | 54.2% | 38.9% | 0.0% | 6.1% | 0.8% |
Detroit Lions | Defensive Field > 20 Yrds | 55.8% | 35.0% | 0.0% | 8.3% | 0.8% |
Detroit Lions | Offensive Field - Not Red Zone | 55.1% | 37.4% | 6.5% | 0.0% | 0.9% |
Detroit Lions | Red Zone | 54.6% | 38.7% | 2.5% | 2.5% | 1.7% |
Green Bay Packers | Own 20 | 59.4% | 30.3% | 0.0% | 9.1% | 1.2% |
Green Bay Packers | Defensive Field > 20 Yrds | 52.8% | 38.2% | 0.0% | 8.3% | 0.7% |
Green Bay Packers | Offensive Field - Not Red Zone | 50.5% | 40.0% | 8.6% | 0.0% | 1.0% |
Green Bay Packers | Red Zone | 55.0% | 38.0% | 0.8% | 5.4% | 0.8% |
Houston Texans | Own 20 | 51.9% | 34.8% | 0.0% | 13.3% | 0.0% |
Houston Texans | Defensive Field > 20 Yrds | 54.8% | 35.7% | 0.0% | 7.0% | 2.5% |
Houston Texans | Offensive Field - Not Red Zone | 51.0% | 35.7% | 13.3% | 0.0% | 0.0% |
Houston Texans | Red Zone | 55.6% | 35.2% | 2.8% | 6.5% | 0.0% |
Indianapolis Colts | Own 20 | 64.7% | 25.3% | 0.0% | 9.5% | 0.5% |
Indianapolis Colts | Defensive Field > 20 Yrds | 59.8% | 32.3% | 0.0% | 7.1% | 0.8% |
Indianapolis Colts | Offensive Field - Not Red Zone | 52.8% | 36.6% | 9.8% | 0.0% | 0.8% |
Indianapolis Colts | Red Zone | 55.9% | 36.6% | 3.4% | 4.1% | 0.0% |
Jacksonville Jaguars | Own 20 | 61.1% | 32.5% | 0.0% | 6.3% | 0.0% |
Jacksonville Jaguars | Defensive Field > 20 Yrds | 51.4% | 37.2% | 0.0% | 8.1% | 3.4% |
Jacksonville Jaguars | Offensive Field - Not Red Zone | 43.0% | 49.7% | 7.3% | 0.0% | 0.0% |
Jacksonville Jaguars | Red Zone | 56.8% | 37.6% | 0.8% | 4.8% | 0.0% |
Kansas City Chiefs | Own 20 | 55.5% | 39.8% | 0.0% | 4.7% | 0.0% |
Kansas City Chiefs | Defensive Field > 20 Yrds | 58.1% | 30.5% | 0.0% | 8.6% | 2.9% |
Kansas City Chiefs | Offensive Field - Not Red Zone | 59.5% | 34.5% | 6.1% | 0.0% | 0.0% |
Kansas City Chiefs | Red Zone | 60.4% | 28.1% | 4.2% | 4.2% | 3.1% |
Los Angeles Rams | Own 20 | 68.1% | 22.1% | 0.0% | 8.8% | 0.9% |
Los Angeles Rams | Defensive Field > 20 Yrds | 50.0% | 39.3% | 0.0% | 9.3% | 1.3% |
Los Angeles Rams | Offensive Field - Not Red Zone | 62.4% | 30.3% | 7.3% | 0.0% | 0.0% |
Los Angeles Rams | Red Zone | 66.0% | 25.8% | 2.1% | 4.1% | 2.1% |
Los Angeles Chargers | Own 20 | 65.2% | 23.0% | 0.0% | 10.4% | 1.5% |
Los Angeles Chargers | Defensive Field > 20 Yrds | 59.9% | 32.8% | 0.0% | 6.6% | 0.7% |
Los Angeles Chargers | Offensive Field - Not Red Zone | 56.8% | 31.8% | 8.1% | 0.0% | 3.4% |
Los Angeles Chargers | Red Zone | 60.4% | 33.0% | 0.9% | 4.7% | 0.9% |
Las Vegas Raiders | Own 20 | 56.4% | 36.8% | 0.0% | 6.8% | 0.0% |
Las Vegas Raiders | Defensive Field > 20 Yrds | 58.2% | 30.3% | 0.0% | 9.0% | 2.5% |
Las Vegas Raiders | Offensive Field - Not Red Zone | 59.3% | 29.7% | 9.3% | 0.0% | 1.7% |
Las Vegas Raiders | Red Zone | 59.8% | 33.3% | 5.7% | 1.1% | 0.0% |
Miami Dolphins | Own 20 | 59.5% | 31.0% | 0.0% | 9.5% | 0.0% |
Miami Dolphins | Defensive Field > 20 Yrds | 60.6% | 31.8% | 0.0% | 6.8% | 0.8% |
Miami Dolphins | Offensive Field - Not Red Zone | 54.2% | 33.1% | 8.5% | 0.0% | 4.2% |
Miami Dolphins | Red Zone | 57.3% | 34.7% | 3.2% | 4.8% | 0.0% |
Minnesota Vikings | Own 20 | 53.3% | 34.7% | 0.0% | 12.0% | 0.0% |
Minnesota Vikings | Defensive Field > 20 Yrds | 59.2% | 32.0% | 0.0% | 7.8% | 1.0% |
Minnesota Vikings | Offensive Field - Not Red Zone | 58.3% | 34.8% | 7.0% | 0.0% | 0.0% |
Minnesota Vikings | Red Zone | 57.0% | 28.0% | 5.6% | 3.7% | 5.6% |
New England Patriots | Own 20 | 48.7% | 39.1% | 0.0% | 9.0% | 3.2% |
New England Patriots | Defensive Field > 20 Yrds | 53.4% | 39.0% | 0.0% | 5.9% | 1.7% |
New England Patriots | Offensive Field - Not Red Zone | 37.9% | 49.2% | 10.5% | 0.0% | 2.4% |
New England Patriots | Red Zone | 50.7% | 37.3% | 3.0% | 6.7% | 2.2% |
New Orleans Saints | Own 20 | 48.1% | 42.3% | 0.0% | 9.5% | 0.0% |
New Orleans Saints | Defensive Field > 20 Yrds | 54.5% | 37.9% | 0.0% | 6.2% | 1.4% |
New Orleans Saints | Offensive Field - Not Red Zone | 52.2% | 36.5% | 10.4% | 0.0% | 0.9% |
New Orleans Saints | Red Zone | 54.9% | 33.6% | 4.1% | 3.3% | 4.1% |
New York Giants | Own 20 | 55.0% | 35.6% | 0.0% | 9.4% | 0.0% |
New York Giants | Defensive Field > 20 Yrds | 36.5% | 52.7% | 0.0% | 9.0% | 1.8% |
New York Giants | Offensive Field - Not Red Zone | 37.2% | 50.4% | 10.2% | 0.0% | 2.2% |
New York Giants | Red Zone | 48.5% | 41.4% | 5.1% | 3.0% | 2.0% |
New York Jets | Own 20 | 59.7% | 27.3% | 0.0% | 11.7% | 1.3% |
New York Jets | Defensive Field > 20 Yrds | 56.0% | 30.7% | 0.0% | 12.0% | 1.2% |
New York Jets | Offensive Field - Not Red Zone | 50.7% | 40.1% | 9.2% | 0.0% | 0.0% |
New York Jets | Red Zone | 58.7% | 31.7% | 3.8% | 1.9% | 3.8% |
Philadelphia Eagles | Own 20 | 49.4% | 39.0% | 0.0% | 9.9% | 1.7% |
Philadelphia Eagles | Defensive Field > 20 Yrds | 48.5% | 45.5% | 0.0% | 6.0% | 0.0% |
Philadelphia Eagles | Offensive Field - Not Red Zone | 36.8% | 54.2% | 5.2% | 0.0% | 3.9% |
Philadelphia Eagles | Red Zone | 47.1% | 43.7% | 1.7% | 5.0% | 2.5% |
Pittsburgh Steelers | Own 20 | 50.9% | 38.5% | 0.0% | 10.6% | 0.0% |
Pittsburgh Steelers | Defensive Field > 20 Yrds | 58.5% | 29.5% | 0.0% | 11.4% | 0.6% |
Pittsburgh Steelers | Offensive Field - Not Red Zone | 49.5% | 38.7% | 9.9% | 0.0% | 1.8% |
Pittsburgh Steelers | Red Zone | 63.8% | 25.9% | 6.0% | 2.6% | 1.7% |
Seattle Seahawks | Own 20 | 54.7% | 39.0% | 0.0% | 6.3% | 0.0% |
Seattle Seahawks | Defensive Field > 20 Yrds | 52.3% | 35.6% | 0.0% | 10.6% | 1.5% |
Seattle Seahawks | Offensive Field - Not Red Zone | 51.4% | 35.8% | 11.9% | 0.0% | 0.9% |
Seattle Seahawks | Red Zone | 50.4% | 38.1% | 4.4% | 2.7% | 4.4% |
San Francisco 49ers | Own 20 | 55.8% | 36.4% | 0.0% | 7.3% | 0.6% |
San Francisco 49ers | Defensive Field > 20 Yrds | 55.2% | 38.8% | 0.0% | 4.5% | 1.5% |
San Francisco 49ers | Offensive Field - Not Red Zone | 42.7% | 49.6% | 7.7% | 0.0% | 0.0% |
San Francisco 49ers | Red Zone | 50.0% | 37.5% | 3.8% | 8.7% | 0.0% |
Tampa Bay Buccaneers | Own 20 | 61.4% | 28.3% | 0.0% | 10.2% | 0.0% |
Tampa Bay Buccaneers | Defensive Field > 20 Yrds | 60.5% | 28.3% | 0.0% | 9.9% | 1.3% |
Tampa Bay Buccaneers | Offensive Field - Not Red Zone | 58.7% | 26.5% | 12.3% | 0.0% | 2.6% |
Tampa Bay Buccaneers | Red Zone | 65.3% | 23.8% | 1.0% | 5.9% | 4.0% |
Tennessee Titans | Own 20 | 40.0% | 48.5% | 0.0% | 11.5% | 0.0% |
Tennessee Titans | Defensive Field > 20 Yrds | 43.2% | 45.3% | 0.0% | 11.5% | 0.0% |
Tennessee Titans | Offensive Field - Not Red Zone | 40.7% | 44.0% | 12.1% | 0.0% | 3.3% |
Tennessee Titans | Red Zone | 32.5% | 55.4% | 0.0% | 4.8% | 7.2% |
Washington Commanders | Own 20 | 53.7% | 31.6% | 0.0% | 13.2% | 1.6% |
Washington Commanders | Defensive Field > 20 Yrds | 58.7% | 32.7% | 0.0% | 8.2% | 0.5% |
Washington Commanders | Offensive Field - Not Red Zone | 58.0% | 33.9% | 8.0% | 0.0% | 0.0% |
Washington Commanders | Red Zone | 45.5% | 48.9% | 1.1% | 4.5% | 0.0% |