NSBA4 · How the Model Works

A full, honest walkthrough of how we turn combine scores, draft positions, and live buzz data into game lines (win probability, point spread, total) and player props.

Methodology reference · regenerated as the model changes · back to index

1 · Philosophy2 · The pipeline3 · Seed ratings 4 · The update5 · Tossup contest6 · Tossups → a game 7 · Home court8 · Making lines9 · Player props 10 · Data & validation11 · Limits & roadmap

1 · Philosophy

We borrow the arc modern sports analytics took: start from a box-score view (who won, final margin), then move to tracking data (every individual event). For science bowl, the "tracking data" is the buzz log — every buzz, who made it, on what subject, whether it was right, and where in the question it happened. That lets us rate players, not just teams, and simulate a game tossup by tossup.

The guiding principle throughout: be honest about uncertainty. NSBA games are high-variance — final margins swing wildly (SD ≈ 57 points) and are only weakly predictable. So the model's natural win probabilities are moderate, and we say so. Where we deliberately sharpen the output for an engaging market, we flag it.

2 · The pipeline at a glance

combine scores ┐
draft position ├─► SEED RATING θ⁰ (per player, per subject)
                 │
live buzz logs ─► ONLINE UPDATE (Elo-style) ─► current rating θ
                 │
                 ▼
  CONTEST SIMULATION (subject-by-subject tossup model + home-court ban)
                 │
                 ▼
  win probability · point spread · game total · player props

The key idea: ratings are the fuel, the simulation is the engine. Everything upstream produces per-player ability numbers; the simulation turns those into a distribution of game outcomes.

3 · Seed ratings — combine shape + draft level

Before any games are played, each player gets a starting ability in each of the six subjects (Biology, Chemistry, Computer Science, Earth/Space, Math, Physics). We use two signals for what each is best at:

We blend them with precision weighting — trust the combine more when it's clean, lean on the draft when it's messy:

m_c = mean combine θ for the player   # combine level
m_d = draft-consensus level for their pick  # from a regression of level on pick value
w_c = 1 / se²    w_d = median(w_c)   # precisions; draft ≈ a median-clean combine
overall = (w_c·m_c + w_d·m_d) / (w_c + w_d)
θ⁰(player, subject) = combine_θ(player, subject) − m_c + overall

So we keep the combine's category-by-category shape but shift the whole player to the draft-informed level. A strong player with a weak combine (drafted high anyway) gets pulled up; a late pick with a flashy combine gets pulled down. Players who didn't take the combine fall back to a draft-only flat profile.

4 · The update — an Elo cousin with direct buzz attribution

Once games are played, we move each player's rating toward what we observe. This is essentially online Bradley–Terry — i.e. Elo — but generalized: ratings live per player × subject, and we update from the actual buzzes.

θ(p, s) ← θ(p, s) + K · ( gets(p,s) − n_s · P(team wins s) · share(p,s) )
gets(p,s) = tossups in subject s the player personally got right this game
n_s = tossups of subject s in the game   share(p,s) = softmax of the player's rating among teammates
K = learning rate = 0.4

Direct attribution is the important part. The credit for a subject goes to the player who actually buzzed it — not split across the lineup by prior strength. This fixes ratings exactly where the prior was wrong: a player the combine underrated in a category rises the moment they score there. (This is the fix that corrected Sean's biology from 0.50 → 1.21 after a 3-for-3 Week 1.)

The learning rate K = 0.4 isn't a guess — it's fit by walk-forward backtest on the prior season (nsba3): seed every player, replay all 53 games in order, predict each game out-of-sample, then update. We sweep K and pick the value that minimizes out-of-sample Brier score. Updating beats the static seed (accuracy 51% → 68%); past K ≈ 0.5 the model gets overconfident, so we sit at the calibrated edge.

Why K is high. A learning rate of 0.4 is aggressive — it means one week of results overwrites a lot of the preseason prior. That's correct here: the combine barely predicts game outcomes, so the model should trust real games quickly.

5 · The tossup contest — who wins a single question

The heart of the engine. For a single tossup in subject s between teams A and B, we model three outcomes — A converts, B converts, or it goes dead (nobody answers):

L(team, s) = logsumexp over the team's players of θ(player, s)  # team strength in s; best player dominates

P(A wins) = e^(β·L_A) / ( e^(β·L_A) + e^(β·L_B) + e^(c_s) )
P(B wins) = e^(β·L_B) / ( … )    P(dead) = e^(c_s) / ( … )

This is Bradley–Terry with a third "phantom competitor" — the question itself, whose strength c_s is how often that subject goes dead. Drop the dead term and it's exactly Elo's win formula. We generalize plain Elo three ways:

The discrimination β = 0.296 and the per-subject deadness c_s are fit by maximum likelihood on every historical tossup. β is small — meaning ability only weakly predicts any single tossup. That's a real finding, and it's why honest game probabilities are moderate.

6 · From tossups to a game — no Monte Carlo needed

A game's margin and total are sums of many independent per-tossup outcomes, so by the Central Limit Theorem they're approximately Normal. We compute the mean and variance in closed form — fast and exact, no simulation. Per subject, with n_s tossups each worth v_s = 4 + 10·(bonus conversion):

E[margin] = Σ_s n_s · v_s · (P_A − P_B)
Var[margin] = Σ_s n_s · v_s² · ( (P_A + P_B) − (P_A − P_B)² )
E[total] = Σ_s n_s · v_s · (P_A + P_B)

The win probability comes from the Normal margin. We deliberately use a wide, empirically-measured spread (RESID_SD = 56, the real game-to-game margin SD) rather than the engine's own narrow internal SD — this keeps single-game probabilities realistic instead of wildly overconfident:

P(home wins) = Φ( expected margin / 56 )

7 · Home court — the category ban

In NSBA, home court isn't a vague "+3 points." It's a concrete mechanic: the home team bans a category, removing one question from it. We model it inside the simulation, not as a fudge factor.

The home team picks the ban that most helps it — usually the away team's strongest subject. We model the choice softly (captains aren't perfectly optimal): for each candidate banned subject, recompute the home team's expected margin, then

P(ban = s) = softmax( λ · margin_if_we_ban_s )   λ = 1
final line = average over the ban distribution
Honest caveat. Because β is small, removing one of ~24 tossups moves the line only a little — so the modeled home edge is currently modest. Week 1 hinted home matters more (home teams went 5–1), but we won't size it up until we have actual data on which categories get banned. λ is a prior until then.

8 · Turning the model into lines

Calibration to points

The raw engine margin is rescaled to real points by a regression on history (spread ≈ 0.31 × raw; totals anchored to nsba3's regular-season scoring). The shrinkage factor reflects how much the engine's confident-looking margins must be pulled toward reality.

Push-proof lines

NSBA scoring is always even (+4 / −4 / +10), so every margin and total is an even number. We exploit that: spreads sit on odd integers, totals on .5 — neither can ever land on the actual result, so a bet can never push (tie). Player-points props use a line of the form 4k+2 for the same reason (a score is always a multiple of 4).

The confidence dial

Pure model output on one week of high-variance data is near pick'em, which is boring for a market. We apply an explicit confidence gain (currently 2.5×) that widens the model's edge on the spread and win probability — clear games get clearer, true coin-flips stay coin-flips. This is a deliberate aggressiveness lever, not a calibration claim; the automated market maker will correct anything wrong. Totals are not gained (they're an environment estimate, not a confidence call).

Market blend: Week-2 per-game markets are untraded platform seeds, so the lines are model-only. (Week 1 leaned 70% on the season futures because there was no game data yet.)

9 · Player props

Props fall right out of the same engine. We take each team's expected tossup wins in a subject and split them among players by their share of the team's strength in that subject:

expected gets(p) = Σ_s n_s · P(team wins s) · share(p, s)
expected points(p) = 4 × expected gets(p)

These are honest expectations — no confidence gain — and they correctly surface the stars (a team's best player gets the lion's share of their subject's tossups). O/U lines sit at 4k+2 so they never push.

10 · Data & validation

Sources

SourceWhat it gives
Combine (IRT)Per-subject ability, the seed shape
Draft orderOverall level / GM consensus
Match JSON (questionLog)Every buzz: player, subject, right/wrong, buzz position, real lineups
ScoresheetsPer-tossup outcomes when the rich JSON isn't available
Season futuresConference-win / top-4 markets (used for preseason team strength)

How we keep it honest

11 · Honest limitations & roadmap

NSBA4 modeling · this page describes the live model and is regenerated as it changes · index · lines · props · ratings