Baseball Savant provides pitch movement leaderboards for each pitch type. As I was looking through the leaderboards for various pitch types, I noticed that several Cubs pitchers stand out in terms of negative horizontal movement compared to average. For instance, Justin Steele’s four-seamer gets the third most cutting movement in the league, and Marcus Stroman and Rowan Wick are also both within the top 20. Having recently read a North Side Bound article about cut-ride, I was curious to see if my observations had any statistical backing.
First, I downloaded a CSV from Baseball Savant of all pitchers a pitcher has thrown at least 50 times this season. I then imported that CSV into my local database and ran a query on it to see the average absolute value of pitch movement per team across both axes. Getting the absolute value is key here so that pitches with a lot of glove-side movement aren’t canceled out by those with a lot of arm-side movement.
The results show that the Cubs are the top team in terms of horizontal pitch movement, and sixth in vertical movement.
This is certainly not the most rigorous method of measuring pitching development on an organizational level. Notably, the query could be improved by using a weighted average, since this analysis didn’t take into account how often specific pitches were being thrown. It’s also not necessarily true that these rankings are correlated with pitching success. It does, however, back up the belief that the Cubs are prioritizing pitchers with outlier horizontal movement.
View the full spreadsheet here. I’ve included the (messy) SQL query I used to calculate these values below as well as a copy of the full table for posterity.
SELECT team_name, avg(abs(diff_z::float)) avg_abs_diff_z, avg(abs(diff_x::float)) avg_abs_diff_x, dense_rank() OVER (ORDER BY avg(abs(diff_x::float)) DESC) AS diff_x_rnk, dense_rank() OVER (ORDER BY avg(abs(diff_z::float)) DESC) AS diff_z_rnk, (dense_rank() OVER (ORDER BY avg(abs(diff_x::float)) DESC) + dense_rank() OVER (ORDER BY avg(abs(diff_z::float)) DESC)) / 2.0 avg_rnk FROM pitch_movement GROUP BY team_name ORDER BY avg_rnk ASC;