FAIR xwOBA Methods

Estimand, chronology, learner, calibration, residual audits, and evidence status

The complete technical specification for the FAIR xwOBA v0.1.0 rolling development study.
Author

Max Gebauer

Published

August 5, 2026

This page specifies the exact model and evidence used in the development article. FAIR xwOBA v0.1.0 is a frozen rolling development candidate. It is not the result of an untouched final-season evaluation, and this page does not authorize any change to the model after seeing partial 2026 results.

What is the estimand?

FAIR estimates realized contact wOBA on matched eligible batted balls. For a contact with five mutually exclusive outcomes—out, single, double, triple, or home run—the model produces probabilities

\[ \mathbf{p}_i = (p_{i,0},p_{i,1B},p_{i,2B},p_{i,3B},p_{i,HR}), \qquad \sum_k p_{i,k}=1. \]

The outcome-value vector is

\[ \mathbf{v}=(0,0.90,1.25,1.60,2.00), \]

and probability-implied xwOBA is

\[ \widehat{xwOBA}^{\,prob}_i=\mathbf{p}_i^\top\mathbf{v}. \]

A separate monotone scalar calibration stage converts that probability-implied value into the published predicted_xwoba. Final scalar predictions are clipped to \([0,2]\).

This is not a defense-independent “quality of contact” estimand. Park, weather, roof status, rule era, and pre-pitch defensive alignment are part of the scoring context. The target is what contact was expected to be worth in that observed environment.

Which contacts enter?

The source window is 2015–2024. Development evaluation covers held-out seasons 2019–2024. A row must be an eligible matched batted-ball contact with an allowed wOBA value, complete scoring keys, and the model’s required prepared features.

The five-class contact target does not cover walks, hit-by-pitches, strikeouts, or other non-contact plate appearances. All FAIR-versus-Statcast metrics therefore describe the exact matched contact panel, not a full plate-appearance offensive metric.

The prepared-data contract uses (season, game_pk, at_bat_number) as the stable contact key. Whole games, rather than individual contacts, are the unit assigned to tuning and probability-calibration groups.

Which inputs may the model use?

The exact whitelist is:

Contact physics

  • launch_speed_mph
  • launch_angle_deg
  • spray_unit_x
  • spray_unit_y
  • hang_time_proxy_s

Environment and rules

  • temperature_delta_f
  • tailwind_exposure
  • headwind_exposure
  • crosswind_exposure
  • park_canonical_id
  • roof_status
  • shift_rule_era

Pre-pitch defensive context

  • if_alignment_v1
  • of_alignment_v1

The wind variables are field-relative and scaled by the contact’s airborne exposure. The hang-time proxy is a deliberately interpretable ballistic approximation, not a measured flight-time feed.

The prediction contract forbids Sprint Speed, player ID, player name, age, height, weight, handedness, position, team, fielder identity, and any downstream realized-event descriptor. Tests also reject common aliases for these fields.

Pre-pitch alignment deserves a qualification. It is player-free at scoring time in the narrow software sense: the predictor matrix receives alignment categories, not a player lookup. But a defense’s positioning can reflect what it knows about a hitter. FAIR is therefore a player-trait-free realized-context model, not a proof that no indirect hitter information exists in its context.

How is time kept honest?

For each outer test season \(y\in\{2019,\ldots,2024\}\):

  1. Training uses seasons 2015 through \(y-2\).
  2. Season \(y-1\) is divided into disjoint tuning and temperature-calibration groups using month-stratified whole games.
  3. The XGBoost learner and its round count are determined without season \(y\).
  4. Temperature scaling is fit only on the calibration games from \(y-1\).
  5. For \(y=2019\), prior scalar calibration is identity because no completed 2018 FAIR out-of-fold prediction panel exists.
  6. For \(y\geq2020\), the isotonic scalar map uses only the completed FAIR predictions from \(y-1\).
  7. The operational early-season PAVA schedule uses the frozen 75% activation rule and a disjoint monitor stream.
  8. The negative-ground out/single correction for year \(y\) uses only completed history before \(y\).
  9. Season \(y\) is scored once.

No random contact split can place two rows from one game in different tuning and calibration roles. No calibrator sees the season it scores. Identity and traits remain unopened until the complete prediction panel has been written and hashed.

What is the backbone learner?

The backbone is multi:softprob XGBoost with five outcome classes and the following frozen parameters:

Table 1: Frozen XGBoost parameters for FAIR xwOBA v0.1.0.
Parameter Value
max_depth 6.000000e+00
eta 2.970000e-02
min_child_weight 2.557060e+01
subsample 7.989000e-01
colsample_bytree 9.369000e-01
gamma 4.822000e-01
lambda 1.777850e+01
alpha 1.537700e+00
seed 2.026051e+07

Training observations use the frozen group-balancing scheme inherited from the verified backbone. Within each season, contact weights are normalized to mean one. Group-level adjustment factors are clipped to the canonical one-third-to-three range before normalization. Player identity is used temporarily only to compute the numeric training weights; the mapping is discarded and cannot reach scoring.

Canonical selected boosting rounds were 1,735 for the 2019 test fold; 2,450 for 2020; 2,336 for 2021; 2,223 for 2022; 2,171 for 2023; and 2,458 for 2024. The public prepared-data implementation records and checks these values when replaying the frozen release specification.

How are probabilities calibrated?

Let \(z_{i,k}\) be the raw class margin for class \(k\). Temperature scaling uses

\[ p^{cal}_{i,k}=\frac{\exp(z_{i,k}/T)}{\sum_j\exp(z_{i,j}/T)}, \qquad T>0. \]

One scalar temperature is fit by minimizing multiclass log loss on the disjoint prior-season calibration games. The fitted temperature is bounded to the verified interval used by the canonical pipeline. The same \(T\) applies to all five margins, preserving their relative structure while adjusting confidence.

Probability calibration is evaluated by log loss and multiclass Brier score:

\[ \text{LogLoss}=-\frac{1}{n}\sum_i\log p^{cal}_{i,y_i}, \]

\[ \text{Brier}=\frac{1}{n}\sum_i\sum_k(p^{cal}_{i,k}-\mathbb{1}[y_i=k])^2. \]

Probabilities must be finite, lie in \([0,1]\), and sum to one within numerical tolerance.

How is scalar xwOBA calibrated?

Probability-implied xwOBA is not assumed to be temporally calibrated merely because the class probabilities have good log loss. The scalar stage is selected and evaluated separately.

For 2019, the prior map is identity. For later folds, a non-decreasing isotonic function is fit from the immediately preceding completed out-of-fold season:

\[ \widehat{xwOBA}^{\,prior}_i=f_{y-1}(\widehat{xwOBA}^{\,prob}_i), \qquad f_{y-1}'(x)\geq0. \]

The operational schedule then applies the frozen early-season PAVA mapping protocol. The schedule’s candidate and monitor streams are disjoint, activation is fixed at 75%, and the map is bounded to \([0,2]\). The public release preserves method labels for both the probability and scalar stages.

Scalar calibration is judged with annual mean residual and a ten-decile calibration gap in addition to RMSE. For decile \(d\),

\[ g_d=\left|\overline{y}_d-\overline{\widehat{xwOBA}}_d\right|, \]

and the reported decile metric is the unweighted mean of the ten \(g_d\) values within a season.

What is the local ground-ball correction?

The final model is the verified backbone plus a narrow probability correction. It activates only when:

  • the hang-time proxy is zero;
  • launch angle is in \([-20,0)\) degrees; and
  • launch speed is in \([55,100]\) mph.

On eligible historical rows, a binomial GAM models the conditional out-versus-single residual using four \(k=4\) cubic smooths: launch angle, launch speed, spray \(x\), and spray \(y\). The fit uses mgcv, REML, and term selection. It requires at least 10,000 eligible history rows. The predicted out/single logit adjustment is clipped to \(\pm0.25\) and redistributes probability only within the existing combined out-plus-single mass. Other class probabilities remain unchanged. If the historical fit is unavailable or fails its contract, the correction is exactly identity.

The correction is learned separately for each outer year using only prior completed predictions and outcomes. It is not a second booster fit and does not use player or trait data.

How is Statcast compared?

Two related but distinct comparators are required.

For scalar RMSE, annual bias, and decile calibration, the comparator is public Statcast xwOBA aligned to the same eligible contacts. This is the familiar public number.

Baseball Savant does not publish the five class probabilities needed for log loss and Brier. Those metrics use a separately declared prior-season-only probability adapter. The adapter is not described as “Statcast’s own probability model.” It is a reproducible bridge that creates a five-class distribution around the public comparator without opening the held-out season.

All tables and figures retain this distinction. A reader should not interpret FAIR’s log-loss advantage as a comparison with an unpublished MLB probability vector.

Which metrics determine the reported result?

The article reports:

  • contact-level RMSE of final scalar xwOBA;
  • five-class log loss;
  • multiclass Brier score;
  • absolute annual mean residual;
  • mean absolute ten-decile calibration gap.

The equal-season summary assigns each of the six development seasons equal weight, regardless of season contact count. A pooled summary is retained in the release as a sensitivity result.

FAIR is lower than Statcast on every reported metric in every development season. Equal-season values are:

Table 2: Equal-season rolling development performance; lower is better.
Model RMSE Log loss Brier Absolute bias Decile gap
FAIR xwOBA 0.3892 0.5053 0.2920 0.0059 0.0099
Statcast xwOBA 0.4376 0.7140 0.3846 0.0139 0.0151

These values establish development superiority, not final promotion.

How are player residuals constructed?

Player identity is joined after prediction freeze using the contact key. For player \(p\) in season \(s\) with \(N_{ps}\) eligible contacts,

\[ r_{ps}=\frac{1}{N_{ps}}\sum_{i\in(p,s)}(y_i-\widehat{xwOBA}_i). \]

The primary persistence analysis requires at least 100 matched contacts in each player-season. Sensitivities use 50 and 150, exclude pairs adjacent to 2020, and exclude the 2022-to-2023 shift-rule transition.

Persistence is centered within season before lag pairing. The primary reported statistic is the contact-weighted Pearson correlation between adjacent player-season residuals. Whole players—not individual contacts or player-seasons—are the resampling unit for paired bootstrap comparisons.

How is Sprint Speed associated with residual value?

Traits are joined only after the three model score panels are aligned. The primary complete-case regression includes standardized Sprint Speed, age, squared age, height, weight, model indicators, and the corresponding model-by-trait interactions. Player-season observations are weighted by matched contact count, and uncertainty is clustered at the player level.

The residual run translation divides the wOBA-value residual by the FanGraphs season-specific wOBA scale. Reported coefficients are then expressed as run-equivalent units per 100 matched BIP per one Sprint Speed SD.

The primary interval is a 5,000-replicate whole-player bootstrap using seed 20260512. The 10th-to-90th percentile season-scale illustration is

\[ 0.7986\times4\times\frac{28.8-25.3}{1.3926}\approx8.03 \]

run-equivalent units across 400 BIP.

This is a conditional descriptive association. It is not a causal speed effect, RE24, baserunning value, WAR, wins, or full-plate-appearance batting runs.

How is the mechanism decomposed?

For each outcome class, the audit calculates actual indicator minus predicted probability. Regressing those probability residuals on standardized Sprint Speed identifies which outcome margins carry the association. Contributions are translated through the outcome-value vector and season wOBA scale, while the scalar-calibration component is retained separately. The probability-class contributions plus scalar component must reconstruct the total run residual within numerical tolerance.

The key descriptive contrast is single probability residual minus out probability residual. FAIR’s estimate is +1.222 percentage points per Sprint Speed SD.

How is persistence “explained” by measured attributes?

The persistence decomposition first estimates lag-one centered weighted correlation on a shared complete-case player panel. It then residualizes player-season errors on:

  1. Sprint Speed alone;
  2. age, height, and weight without Sprint Speed; and
  3. all measured traits together.

The relative reduction is

\[ \frac{\rho_{raw}-\rho_{residualized}}{\rho_{raw}}. \]

For FAIR, the all-trait reduction is 51.3%; for Statcast it is 21.5%. These are not additive variance components or causal shares. Samples differ slightly between specifications when complete-case requirements differ, which is why the article’s sequential figure uses the shared all-trait panel for its before/after endpoints.

What is the evidence status?

The exact FAIR candidate uses 2015–2024 source seasons and scores 2019–2024 out of fold. Its canonical candidate construction did not open 2025 or 2026. The broader project had already examined 2025 before this final framing, so the release labels the result rolling development evidence rather than an untouched validation.

Partial 2026 data are monitoring-only and cannot change features, parameters, calibration rules, thresholds, examples, figures, or claims. The completed untouched-season evaluation will be a separate immutable release. Version 1.0 is reserved for a successful locked confirmation.

The public name FAIR maps to the unchanged verified internal candidate ID defensive_negative_ground_pair_gam_v1. That technical identifier and all canonical hashes remain in the release manifest for provenance; it is not a second public model.