Question:

Who are the five best starting pitchers in Major League Baseball right now (ignore contract status, age, etc)?

This project begins with a brief statistical analysis over the last two seasons to pick ten candidates. It then summarizes a video scouting evaluation to determine the final order, which can be found at the bottom of the page.

library(dplyr)
## Warning: package 'dplyr' was built under R version 4.2.3
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
library(baseballr)
## Warning: package 'baseballr' was built under R version 4.2.3
# load season data. Use 2022 and 2023 (through present date)
load("G:/My Drive/Baseball/Summer 2023/R Projects/Data/Statcast2022.RData")
load("G:/My Drive/Baseball/Summer 2023/R Projects/Data/Statcast2023.RData")

Statcast2223 <- rbind(Statcast2022, Statcast2023)

Create a table to display the statistical leaders over the given time period. The areas of interest are xwOBA-against (wOBA-against for context), K%, and BB%.

These metrics eliminate nearly all factors outside of a pitcher’s control. They give the truest indication of his performance by eliminating the noise associated with common-place statistics like ERA and W-L.

# Get unique values from the 'pitcher' column of Statcast2223
unique_playerID <- unique(Statcast2223$pitcher)

# Create empty data frame for pitchers2223
pitchers2223 <- data.frame()

# Define label vectors and counts

hits_vector <- c('single', 'double', 'triple', 'home_run')
at_bats_vector <- c('field_out', 'strikeout', 'grounded_into_double_play', 
                    'fielders_choice', 'fielders_choice_out', 'triple_play', 
                    'strikeout_double_play', 'double_play', 'field_error', '
                    force_out', hits_vector)
plate_appearances_vector <- c(at_bats_vector, 'sac_fly', 'walk', 'hit_by_pitch', 
                              'sac_bunt', 'sac_bunt_double_play', 
                              'sac_fly_double_play', 'catcher_interf')

# Loop through each unique player ID

for (player_id in unique_playerID) {
  
  # Filter Statcast2223 data for the current player ID and game_type == 'R'
  filtered_data <- Statcast2223 %>%
    filter(pitcher == player_id & game_type == 'R')
  
  # Define count labels
  walk_count <- sum(filtered_data$events == 'walk')
  strikeout_count <- sum(filtered_data$events == 'strikeout')
  hit_by_pitch_count <- sum(filtered_data$events == 'hit_by_pitch')
  pitch_count <- nrow(filtered_data)
  edge_count <- sum(filtered_data$edge, na.rm = TRUE)
  
  # Calculate desired metrics
  # Calculate batters faced (bf)
  pa <- sum(filtered_data$events %in% plate_appearances_vector)
  
  # Calculate xwOBA against
  xwoba_sum <- sum(filtered_data$estimated_woba_using_speedangle, na.rm = TRUE) +
                0.7 * (walk_count + hit_by_pitch_count)
  woba_denominator <- sum(filtered_data$events %in% at_bats_vector) +
    walk_count +
    hit_by_pitch_count +
    sum(filtered_data$events == 'sac_fly')
  xwoba <- xwoba_sum / woba_denominator
  
  # Calculate wOBA against
  woba_sum <- sum(filtered_data$woba_value, na.rm = TRUE)
  woba <- woba_sum / woba_denominator
  
  # Calculate K%
  strikeout_rate <- strikeout_count / pa

  # Calculate BB%
  walk_rate <- walk_count / (pa - hit_by_pitch_count)

  # Create a row for the current player in pitchers222323
  new_row <- data.frame(player_id = player_id, 
                        bf = pa,
                        xwoba = xwoba,
                        woba = woba,
                        k = strikeout_rate,
                        bb = walk_rate,
                        stringsAsFactors = FALSE)
  
  # Append the new row to pitchers2223 data frame
  pitchers2223 <- rbind(pitchers2223, new_row)
}

# Filter to only include BF >= 894 (3 per team game over selected time period)

pitchers2223 <- filter(pitchers2223, bf >= 894)

# Create player info table and join 
  
mlb_stats23 <- mlb_stats(stat_type = 'season', player_pool = 'All', stat_group = 'pitching', 
                           season = 2023)

player_info23 <- mlb_stats23 %>%
  select(player_id, player_first_name, 
         player_last_name,
         team_name)

pitchers2223 <- pitchers2223 %>%
  left_join(player_info23, by = 'player_id') %>%
  select(player_id, player_first_name, player_last_name,
         team_name, everything())

pitchers2223 <- pitchers2223 %>%
  rename(first = player_first_name,
         last = player_last_name,
         team = team_name)

head(pitchers2223, 10)
##    player_id   first       last                 team   bf     xwoba      woba
## 1     506433      Yu    Darvish     San Diego Padres 1327 0.2960596 0.2927979
## 2     425844    Zack    Greinke   Kansas City Royals 1053 0.3478384 0.3505703
## 3     664285 Framber     Valdez       Houston Astros 1463 0.3040103 0.2991078
## 4     608331     Max      Fried       Atlanta Braves  951 0.2641495 0.2780526
## 5     669203  Corbin     Burnes    Milwaukee Brewers 1444 0.2826064 0.2828829
## 6     425794    Adam Wainwright  St. Louis Cardinals 1177 0.3629847 0.3609455
## 7     660271  Shohei     Ohtani   Los Angeles Angels 1174 0.2801399 0.2800341
## 8     571578 Patrick     Corbin Washington Nationals 1355 0.3852986 0.3941242
## 9     669456   Shane     Bieber  Cleveland Guardians 1257 0.3160096 0.3035543
## 10    675911 Spencer    Strider       Atlanta Braves 1155 0.2584762 0.2658442
##            k         bb
## 1  0.2539563 0.06044376
## 2  0.1433998 0.04202483
## 3  0.2447027 0.07617729
## 4  0.2450053 0.04545455
## 5  0.2839335 0.07659874
## 6  0.1571793 0.07271172
## 7  0.3287905 0.08527132
## 8  0.1749077 0.07137546
## 9  0.2315036 0.05511182
## 10 0.3870130 0.08041958
# Add ranking columns

pitchers2223_ranked <- pitchers2223 %>%
  mutate(xwoba_r = rank(xwoba),
         woba_r = rank(woba),
         k_r = rank(desc(k)),
         bb_r = rank(bb))

head(pitchers2223_ranked, 10)
##    player_id   first       last                 team   bf     xwoba      woba
## 1     506433      Yu    Darvish     San Diego Padres 1327 0.2960596 0.2927979
## 2     425844    Zack    Greinke   Kansas City Royals 1053 0.3478384 0.3505703
## 3     664285 Framber     Valdez       Houston Astros 1463 0.3040103 0.2991078
## 4     608331     Max      Fried       Atlanta Braves  951 0.2641495 0.2780526
## 5     669203  Corbin     Burnes    Milwaukee Brewers 1444 0.2826064 0.2828829
## 6     425794    Adam Wainwright  St. Louis Cardinals 1177 0.3629847 0.3609455
## 7     660271  Shohei     Ohtani   Los Angeles Angels 1174 0.2801399 0.2800341
## 8     571578 Patrick     Corbin Washington Nationals 1355 0.3852986 0.3941242
## 9     669456   Shane     Bieber  Cleveland Guardians 1257 0.3160096 0.3035543
## 10    675911 Spencer    Strider       Atlanta Braves 1155 0.2584762 0.2658442
##            k         bb xwoba_r woba_r k_r bb_r
## 1  0.2539563 0.06044376      23     17  26   23
## 2  0.1433998 0.04202483      80     71  86    2
## 3  0.2447027 0.07617729      29     21  33   52
## 4  0.2450053 0.04545455       2      4  32    3
## 5  0.2839335 0.07659874       9      9  12   53
## 6  0.1571793 0.07271172      86     82  84   49
## 7  0.3287905 0.08527132       8      6   2   68
## 8  0.1749077 0.07137546      87     87  78   46
## 9  0.2315036 0.05511182      40     22  43   15
## 10 0.3870130 0.08041958       1      1   1   59

View the top performers in each statistic and select top 10 for further consideration.

xwoba_table <- pitchers2223_ranked %>%
  select(first, last, team, xwoba, woba, xwoba_r) %>%
  arrange(xwoba)

head(xwoba_table, 10)
##      first      last                  team     xwoba      woba xwoba_r
## 1  Spencer   Strider        Atlanta Braves 0.2584762 0.2658442       1
## 2      Max     Fried        Atlanta Braves 0.2641495 0.2780526       2
## 3  Clayton   Kershaw   Los Angeles Dodgers 0.2723424 0.2765439       3
## 4      Max  Scherzer         Texas Rangers 0.2738767 0.2800441       4
## 5   Freddy   Peralta     Milwaukee Brewers 0.2776477 0.2925615       5
## 6   Justin Verlander        Houston Astros 0.2788445 0.2682587       6
## 7     Zack   Wheeler Philadelphia Phillies 0.2796069 0.2877592       7
## 8   Shohei    Ohtani    Los Angeles Angels 0.2801399 0.2800341       8
## 9   Corbin    Burnes     Milwaukee Brewers 0.2826064 0.2828829       9
## 10   Aaron      Nola Philadelphia Phillies 0.2839432 0.2988176      10
k_table <- pitchers2223_ranked %>%
  select(first, last, team, k, k_r) %>%
  arrange(desc(k))

head(k_table, 10)
##      first       last               team         k k_r
## 1  Spencer    Strider     Atlanta Braves 0.3870130   1
## 2   Shohei     Ohtani Los Angeles Angels 0.3287905   2
## 3    Blake      Snell   San Diego Padres 0.3201377   3
## 4   Freddy    Peralta  Milwaukee Brewers 0.3043478   4
## 5   Hunter     Greene    Cincinnati Reds 0.3037281   5
## 6   Gerrit       Cole   New York Yankees 0.3032170   6
## 7    Kevin    Gausman  Toronto Blue Jays 0.3016345   7
## 8      Max   Scherzer      Texas Rangers 0.2987698   8
## 9    Jesus    Luzardo      Miami Marlins 0.2937063   9
## 10   Shane McClanahan     Tampa Bay Rays 0.2911275  10
bb_table <- pitchers2223_ranked %>%
  select(first, last, team, bb, bb_r) %>%
  arrange(bb)

head(bb_table, 10)
##      first    last                  team         bb bb_r
## 1   George   Kirby      Seattle Mariners 0.03166227    1
## 2     Zack Greinke    Kansas City Royals 0.04202483    2
## 3      Max   Fried        Atlanta Braves 0.04545455    3
## 4    Corey  Kluber        Boston Red Sox 0.04580153    4
## 5    Aaron    Nola Philadelphia Phillies 0.04881356    5
## 6  Braxton Garrett         Miami Marlins 0.04923414    6
## 7    Miles Mikolas   St. Louis Cardinals 0.04938272    7
## 8    Kevin Gausman     Toronto Blue Jays 0.05067064    8
## 9     Zack Wheeler Philadelphia Phillies 0.05084746    9
## 10   Logan    Webb  San Francisco Giants 0.05230557   10

10 pitchers chosen for consideration:

  • Spencer Strider, RHP, ATL
  • Max Scherzer, RHP, TEX
  • Shohei Ohtani, RHP, LAA
  • Freddy Peralta, RHP, MIL
  • Blake Snell, LHP, TB
  • Dylan Cease, RHP, CWS
  • Max Fried, LHP, ATL
  • Hunter Greene, RHP, CIN
  • Corbin Burnes, RHP, MIL
  • Aaron Nola, RHP, PHI

The remaining evaluation is based on video scouting. Full-start videos accessed via https://www.youtube.com/@DawgHen0

Spencer Strider, ATL

Pitch Grades

FB: 80 SL: 70

Report Summary

Strider has arguably the best FB in baseball. His above-average extension and release point give him a uniquely-low approach angle, which adds deception and perceived velocity. The plus SL creates a very effective tunnel at the bottom of the zone. His FB characteristics allow him to miss bats, even when command lacks. He can dominate most hitters with simply middle/middle FBs.

Max Scherzer, TEX

Pitch Grades

FB: 70 SL: 70 CB: 70 CH: 65 CT: 60

Report Summary

Scherzer is very effective pitching to the edges of the zone, working through FB-SL and FB-CH combos. CB and CT become more prevalent in subsequent trips through the batting order, which allows him to dominate deep into games.

Shohei Ohtani, LAA

Pitch Grades

FB: 80 SI: 80 SL: 70 SP: 60 CB: 55

Report Summary

Ohtani has elite 100+ velocity, but he utilizes a heavy-SL approach to slow down hitters’ eyes, pitching backwards to FB/SI for putout. He changes eye levels effectively, giving him the ability to get chases down on SL and CB. He hides the ball well through his stride, increasing deceptiveness.

Freddy Peralta, MIL

Pitch Grades

FB: 60 SL: 70 CB: 55 CH: 55

Report Summary

Peralta has a great four-pitch mix, with plenty of effective sequencing options. He consistently lives down in the zone, elevating for Ks. He is capable of leading with the CB at times, and CB-SL is a great combo, as they take similar shapes with a 6-7mph difference. He does a great job of controlling ABs and keeping hitters off-balance.

Blake Snell, TB

Pitch Grades

FB: 70 SL: 70 CB: 55 CH: 55

Report Summary

Snell creates a big downward angle from release, which makes his FB and SL look very similar out of the hand. He pitches to the edges and just off of the plate, living with the occasional walk, but this allows him to utilize his best combos (FB-SL and CH-SL) for chases.

Dylan Cease, CWS

Pitch Grades

FB: 70 SL: 60 CB: 70

Cease lives at the top of the zone with high plus velocity, and he works the SL off of that plane. The CB could be his best pitch if it were more consistent, featuring elite spin and dive. His quick arm action hides the ball well. His offering can get a little thin when he cannot command the CB for strikes.

Max Fried, ATL

Pitch Grades

FB: 60 CB: 80 CH: 55 SI: 55 SL: 55

Report Summary

Fried has one of the deepest arsenals in baseball, with five above-average pitches with >10% usage. The big CB is his calling card, and it allows him to move up and down in the zone with command. He has one of the lowest walk rates in the league, and he does so while staying out of the middle of the zone.

Hunter Greene, CIN

Pitch Grades

FB: 80 SL: 70 CH: 60

Report Summary

The 100+ FB locates and plays well to all parts of the plate. This gives him effective “combos” by simply moving the FB around the zone. This is his primary approach in first trips through the order. In subsequent trips, he features the tight-spin SL, which prevents hitters from sitting and timing his FB. Offspeed command can be inconsistent at times, but when it clicks, he can put up strikeout numbers near the top of the league.

Corbin Burnes, MIL

Pitch Grades

CT: 80 CB: 55 CH: 70 SI: 55 SL: 60

Report Summary

Burnes has an elite CT that functions as his primary fastball. He moves it in and out very well, starting at the edges and inducing chases and takes for strikes. The similarly-shaped SL creates a strong combo, and it comes out later in outings. The SI, though rare, gives him a second velocity offering that hitters never expect.

Aaron Nola, PHI

FB: 60 CB: 70 SI: 50 CH: 60 CT: 50

Report Summary

Nola has an elite arsenal that primarily features FB, SI, and CB. The CB starts flat with big drop and pairs nicely with the FB. He has an elite ability to hit spots on the edges of the zone, giving hitters very few opportunities to capitalize on mistakes.

Final Rankings

1. Spencer Strider

2. Shohei Ohtani

3. Max Scherzer

4. Blake Snell

5. Corbin Burnes

  1. Max Fried
  2. Aaron Nola
  3. Freddy Peralta
  4. Hunter Greene
  5. Dylan Cease