Stuff+/Location+/Pitching+ Model and Dashboard

During the 2025 NECBL season, I worked to find a way to better capture a pitcher’s actual talent, their ability to spot up their pitches effectively, and how effective their overall process is. This led to the creation of Stuff+, Location+, and Pitching+ models for the NECBL. The data sample consisted of 350,000 pitches from the 2021-2025 seasons. After cleaning (standardizing “PitchCall” values, correcting random typos throughout the files, and removing instances of position player pitching), the data was filtered down to approximately 330,000 pitches, which were then split 70/30 for training/validation. I trained three separate Random Forest models, each with 250 trees, as any value beyond that number showed diminishing returns.  Each model predicts outcome probabilities and converts them to expected run value (xRV), which is then scaled to where 100 represents league average and each 10 points equals one standard deviation (anything above 100 is above average, anything below 100 is below average). Stuff+ uses only physical characteristics (velocity, spin, movement, release characteristics, and approach angles) to predict “PitchCall” outcomes to measure raw pitch quality. Location+ isolates command using only location and count data (along with both pitcher and batter dexterity as well as pitch type). Pitching+ is not simply a combination of the previous two; instead, it captures how all components interact to measure the complete expected run value using all available features. Each model generates both arsenal-wide scores and individual pitch-type scores. I felt confident with the calibration, as the average run value per pitch was -0.0066, while my xRV per pitch came to -0.0068, favoring pitchers slightly more than in reality. The Brier score came out to 0.054.


Pitching+ Dashboard

The next tab is the Complete Board, which is simply a complete leaderboard showing every pitcher's overall Stuff+, Location+, and Pitching+ scores (again their complete arsenal). I merged the three datasets using left_join by pitcher name. The table displays pitcher name, team, and all three scores side by side, sorted by Pitching+ in descending order. Below the rankings, I added a distribution plot that overlays histograms for Stuff+, Location+ and Pitching+.

The Pitch Type Complete Board tab is, again, almost identical to its arsenal-wide equivalent “Complete Board” tab, but filters down further to each specific pitch type. I used inner_join to merge the three pitch-type specific datasets (pitching_pitch, stuff_pitch, location_pitch) by both Pitcher and TaggedPitchType. The table shows pitcher name, pitch type, team, and all three scores (Stuff+, Location+, Pitching+), sorted alphabetically by pitcher and then by pitch type.


The first tab, which contains the overall Leaderboards, displays the top 10 pitchers in Stuff+, Location+, and Pitching+ (defaults to the 2025 season) for an an entire arsenal. Each table shows the name, their score, and team. The scores are color-coded using a gradient scale where values above 100 (league average) appear in darker shades of green, while below-average scores shift through lighter shades down to red, with each 10-points being one standard deviation. The tables automatically filter based on the season, team, and handedness selections in the sidebar.

The Pitch Type Rankings tab functions similarly to the Complete Rankings tab but filters further to a single pitch type selected from a dropdown at the top (defaulted to Curveball). Similar to all other tabs, I used inner_join to merge the three pitch type-specific datasets by both Pitcher and TaggedPitchType, filtering for the selected pitch type. The table then displays every pitcher who throws that specific pitch. Below the table, I added a distribution plot that shows a histogram of Pitching+ scores specifically for that pitch type. The dropdown updates both the table and the distribution plot, and all sidebar filters for season, team, and handedness remain in effect.

The Pitch Type tab is almost identical to the Overall Leaderboards tab, but filters down to a specific pitch type selected from a dropdown menu at the top of the page. I created a dropdown for pitch type selection with options for Fastball, Slider, Curveball, Changeup, Cutter, Sinker, and Sweeper, defaulted to Fastball. The tables update reactively whenever you change the pitch type dropdown, automatically updating based on the specifications.

The Player Search tab allows you to search for any individual pitcher and view all data on them. I put in a text input box where you enter a player's name and click a search button to trigger the search. The search uses a case-insensitive partial match, so, for example, typing "kittrell" would find "Kittrell, Zach" even with different capitalization.

Once you click search, the tab displays two sections. The first of which being the Player Details section, which shows their arsenal-wide Stuff+, Location+, and Pitching+ scores. Below that is "Player Arsenal,” which gives you the individual pitch type breakdowns for the selected player.

Next
Next

xwOBA/xwOBACON Model and Dashboard