2  RB Rankings

2.1 Packages Needed

library(tidyverse)
library(cfbfastR)
library(DT)

2.2 Load Play-by-Play Data

pbp_2025 <- load_cfb_pbp(seasons = 2025) # mean epa/dropback

2.3 Load RB Players

rbs <- read.csv("data/players.csv") %>% filter(position == "HB")
head(rbs)
                 name     id position       team rank
1      Jeremiyah Love 171090       HB Notre Dame    3
2      Jadarian Price 156985       HB Notre Dame   56
3 Mike Washington Jr. 145672       HB   Arkansas   71
4       Jonah Coleman 158717       HB Washington   99
5        Seth McGowan 122936       HB   Kentucky  127
6      Emmett Johnson 156473       HB   Nebraska  137

2.4 Load Necessary CSV Files

rushing <- read.csv("data/rb/rushing_summary.csv") %>% 
  select(player_id, grades_run, yco_attempt, attempts, fumbles) # rush grade, yac/attempt, fum%
receiving <- read.csv("data/receiving_summary.csv") %>% 
  select(player_id, grades_pass_block, yprr, grades_pass_route) # rec grade, yprr, pb grade

2.5 Combine Datasets and Pull Names

rb_values <- rbs %>% 
  left_join(rushing, by = c("id" = "player_id")) %>% 
  drop_na()
rb_values <- rb_values %>% 
  left_join(receiving, by = c("id" = "player_id")) %>% 
  drop_na()
rb_values <- rb_values %>% 
  mutate(fum_p = round((fumbles/attempts)*100, 2)) %>% 
  select(-attempts, -fumbles) %>% # get fum%
  rename(rush_grade = grades_run, yac_att = yco_attempt, pb_grade = grades_pass_block, rec_grade = grades_pass_route)
rb_names <- rb_values %>% pull(name)

2.6 Calculate Mean EPA and Combine

rusher_epa <- pbp_2025 %>%
  filter(rush == 1) %>%
  group_by(rusher_player_name) %>%
  summarize(mean_epa = round(mean(EPA, na.rm = TRUE), 3)) %>%
  filter(!is.na(rusher_player_name), rusher_player_name %in% rb_names) %>%
  rename(name = rusher_player_name) %>%
  arrange(-mean_epa)

rb_values <- left_join(rb_values, rusher_epa, by = "name") %>% select(-id)

2.7 Get Mean Values (for testing)

mean(rb_values$rush_grade)
[1] 78.04571
mean(rb_values$yac_att)
[1] 3.156571
mean(rb_values$pb_grade)
[1] 48.96857
mean(rb_values$yprr)
[1] 0.9597143
mean(rb_values$rec_grade)
[1] 59.48
mean(rb_values$fum_p)
[1] 1.039143
mean(rb_values$mean_epa)
[1] 0.02751429

2.8 Create Rating Function

get_rb_ratings <- function(input_df) {
  df_rb_copy <- input_df %>% mutate(
    rush_grade = round(pmax(pmin((rush_grade-70) / 2, 10), 0), 2), # 70-90, mean 80
    yac_att = round(pmax(pmin((yac_att-2.5) * 5, 10), 0), 2), # 2.5-4.5, mean 3.5
    mean_epa = round(pmax(pmin((mean_epa) * 50, 10), 0), 2), # 0-.2, mean .1
    yprr = round(pmax(pmin((yprr-0.5) * 5, 5), 0), 2), # 0.5-1.5, mean 1, worth 5
    pb_grade = round(pmax(pmin((pb_grade-35) / 6, 5), 0), 2), # 35-65, mean 50, worth 5
    rec_grade = round(pmax(pmin((rec_grade-50) / 4, 5), 0), 2), # 50-70, mean 60, worth 5
    fum_p = round(pmax(pmin(((100-fum_p)-98) * 3.33, 5), 0), 2), # 2-0.5, mean 1.25, worth 5
  )
  
  return(df_rb_copy)
}

2.9 Create Final Dataset

rb_ratings <- get_rb_ratings(rb_values) %>% 
  mutate(total = rowSums(select(.,-name, -position, -team, -rank))) %>% 
  arrange(-total) #%>%
  #mutate(pos_rank_aft = row_number())

2.10 Display Ratings

datatable(rb_ratings)