Whiffs is a comprehensive evaluation of MLB projection system accuracy, comparing Marcel, Steamer, and ZiPS projections against actual player performance from 2010-2024.
The analysis follows Tom Tango's methodology for evaluating projection systems, adjusting for league averages and weighting errors by playing time to provide meaningful accuracy metrics.
Visit Whiffs.org to explore the interactive charts and analysis.
Whiffs implements three key principles from Tom Tango's posts on projection evaluations:
- Playing time (PA/BF) is evaluated independently from rate statistics
- Prevents misleading assessments where playing time and rate errors cancel out
- Rate stats are normalized per plate appearance (PA) or batters faced (BF)
- Errors are calculated after adjusting for projected vs actual league averages
- Ensures projections are evaluated on their ability to predict player performance relative to league context
- A player performing at league average should be projected as league average, regardless of raw numbers
- Errors are weighted by actual playing time (PA/BF) to reflect real-world impact
- A projection error for a 600 PA player matters more than the same error for a 100 PA player
- Prevents systems from being equally penalized for mistakes on marginal vs regular players
See more at Whiffs Methodology.
Whiffs evaluations and site are built in Python.
Python: Install Python from python.org or your package manager.
uv: Install uv if you haven't already and then collect dependencies with:
uv syncNode.js: Install Node.js for the Tailwind CLI, then:
npm installProjections and stats are not included in the repository, so you'll need to build or find those first.
-
Fetch MLB Stats Data
python utils/fetch_mlb_stats.py
First, you need the actual player stats. This will download actual player statistics from MLB's Stats API for 2007-2024 into the
/statsdirectory. These are needed for building the Marcel projections and for assessing projection accuracy.This will also collect some biographical data, as birthdates are needed for building Marcels.
-
Build Marcels
python utils/marcel-like.py
Builds Marcel-like projections into
/projectionsusing the MLB data from Step 1.Note: these differ somewhat from the official Marcel projections. If you can improve my code, please go for it!
-
Add historical Steamer and ZiPS from FanGraphs
Historical Steamer and ZiPS projections are available on FanGraphs for members.
Whiffs expects these to be in the
/projectionsdirectory in a format likesteamer_2012_bat.csv.
Once you've got all your stats and projection data in place:
npm run allThat runs evaluation, HTML rendering, and CSS in sequence. Individual steps:
# Projection evaluation + write reports/site_cache/ (no HTML)
npm run evals
# Re-render HTML from cache into _site/ (requires a prior evals)
npm run site
# Compile Tailwind CSS into _site/assets/css/style.css
npm run cssUse npm run all (or at least evals) when projection/stats data changes. For template iteration, npm run site (and npm run css if you added new Tailwind classes). For theme-only tweaks to input.css, npm run css alone is enough.
npm run serveThen open http://localhost:8080
This project is licensed under the MIT License.
See the LICENSE file for full details.
I'm hoping to add more historical projections to the comparison set. If you've saved some, or if you are the creator of a projection system, contact me and I'll be happy to add them to the analysis.