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)
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
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
The remaining evaluation is based on video scouting. Full-start videos accessed via https://www.youtube.com/@DawgHen0
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.