library(tidyverse)
library(cfbfastR)
library(DT)1 QB Rankings
1.1 Packages Needed
1.2 Load Play-by-Play Data
pbp_2025 <- load_cfb_pbp(seasons = 2025) # mean epa/dropback1.3 Load QB Players
qbs <- read.csv("data/players.csv") %>% filter(position == "QB")1.4 Load Necessary CSV Files
passing <- read.csv("data/qb/passing_summary.csv") %>%
select(player, grades_pass, qb_rating, twp_rate, btt_rate) # pass grade, qb rating, tw%, btt%1.5 Combine Datasets and Pull Names
qb_values <- qbs %>%
left_join(passing, by = c("name" = "player")) %>%
drop_na()
qb_names <- qb_values %>% pull(name)1.6 Calculate Mean EPA and Combine
passer_epa <- pbp_2025 %>%
filter(pass == 1) %>%
group_by(passer_player_name) %>%
summarize(mean_epa = round(mean(EPA, na.rm = TRUE), 3)) %>%
filter(!is.na(passer_player_name), passer_player_name %in% qb_names) %>%
rename(name = passer_player_name) %>%
arrange(-mean_epa)
qb_values <- left_join(qb_values, passer_epa, by = "name") %>% select(-id)1.7 Get Mean Values (for testing)
mean(qb_values$grades_pass)[1] 74.33333
mean(qb_values$qb_rating)[1] 97
mean(qb_values$twp_rate)[1] 3.225926
mean(qb_values$btt_rate)[1] 4.692593
mean(qb_values$mean_epa)[1] 0.1962222
1.8 Create Rating Function
get_qb_ratings <- function(input_df) {
input_df <- input_df %>% mutate(
grades_pass = round(pmax(pmin((grades_pass-70) / 2, 10), 0), 2), # 70-90, mean 80
qb_rating = round(pmax(pmin((qb_rating-90) / 3, 10), 0), 2), # 90-120, mean 105
twp_rate = round(pmax(pmin(((100-twp_rate)-96) * 5, 10), 0), 2), # 4-2, mean 3
btt_rate = round(pmax(pmin((btt_rate-3) * 3.33, 10), 0), 2), # 3-6, mean 4.5
mean_epa = round(pmax(pmin((mean_epa) * 33.33, 10), 0), 2), # 0-.3, mean .15
)
return(input_df)
}1.9 Create Final Dataset
qb_ratings <- get_qb_ratings(qb_values) %>%
mutate(total = rowSums(select(.,-name, -position, -team, -rank))) %>%
arrange(-total) #%>%
#mutate(pos_rank_aft = row_number())1.10 Display Ratings
datatable(qb_ratings)