Wins-First CFB Top-25 (Kai Morales)

Methodology, Formulas & Algorithm

An objective, reproducible ranking model: week-of-game Coaches Poll ranks, Power-4 weighting, schedule strength, and diminishing returns on unranked wins.

This is Disclaimer: This model isn’t meant to predict game outcomes — it’s a dynamic, unbiased ranking system. However, its results often highlight inconsistencies or biases in the AP Poll.

View Past Rankings

Model vs. AP Poll

Github

Abstract

I noticed that traditional media polls can be reputation-driven. This model replaces subjective ranking with a wins-first, transparent scoring system. Each game receives a value based on (i) opponent quality at the week of play via the Coaches Poll, (ii) location and capped margin, (iii) Power-4 vs. Group-of-5 tier for unranked opponents, and (iv) a season-level strength-of-schedule multiplier.


Core Ideas

  • Week-of-game ranks: Upsets valued when they occurred, not retroactively.
  • Conference tiering: Unranked P4 wins > unranked G5 wins; G5 losses sting more.
  • SOS scaling: Season-level multiplier based on average opponent quality.
  • Parsimony: Few transparent knobs; no black box.
Bias note: Journalist voting can overweight legacy brands. We rely on the Coaches Poll only as a signal, and only at week-of-game.

Tooling

Python, Pandas, cfbd API, python-dotenv, Certifi


Formulas

Opponent Rank Quality (week-of-game)

Rank quality \(rq\) (1 is best) maps to \([0,1]\):

$$ rq(r) = 1 - \frac{r - 1}{24}, \quad r \in \{1,\dots,25\}. $$

Location & Margin

Location multiplier: $$ L=\begin{cases} 1.04 & \text{Road} \\ 1.00 & \text{Neutral} \\ 0.985 & \text{Home} \end{cases} $$ Margin is capped: \( m'=\min(m,\,14) \).

Win margin bonus: $$ \text{WinMargin}(m') = 1 + \gamma \cdot m', \quad \gamma = 0.008. $$

Close-loss relief (with floor \(\rho\)): $$ \text{Relief}(m') = \max\!\bigl(\rho,\; 1 - \lambda \cdot m'\bigr), \quad \rho=0.70,\;\lambda=0.01. $$

Ranked Scaling

Ranked wins get a multiplicative boost; ranked losses get a discount: $$ \text{WinBoost} = 1 + \beta \cdot rq, \qquad \text{LossDiscount} = 1 - \delta \cdot rq, $$ with \(\beta=0.70\), \(\delta=0.40\).

Unranked Opponent Tiering (P4 vs G5/Ind)

For unranked opponents, apply conference-tier multipliers: $$ s_{\text{win}}=\begin{cases} 0.85 & \text{P4 opponent} \\ 0.40 & \text{G5/Independent} \end{cases} \qquad k_{\text{loss}}=\begin{cases} 1.05 & \text{P4 opponent} \\ 1.30 & \text{G5/Independent} \end{cases} $$

Per-Game Value

Win:

$$ \text{base}_W = \bigl(1 + \alpha_W \, Q_{\text{opp}}\bigr)\, L \,\text{WinMargin}(m'), \quad \alpha_W=0.6 $$ $$ \text{value}_W = \begin{cases} \text{base}_W \cdot s_{\text{win}} \cdot \text{WinBoost}, & \text{opp unranked (tiered)} \\\\ \text{base}_W \cdot \text{WinBoost}, & \text{opp ranked} \end{cases} $$

Loss:

$$ \text{base}_L = \bigl(B + \alpha_L \, Q_{\text{opp}}\bigr)\, L \,\text{Relief}(m'), \quad B=0.90,\; \alpha_L=0.3 $$ $$ \text{value}_L = \begin{cases} -\text{base}_L \cdot k_{\text{loss}} \cdot \text{LossDiscount}, & \text{opp unranked (tiered)} \\\\ -\text{base}_L \cdot \text{LossDiscount}, & \text{opp ranked} \end{cases} $$

Season-Level Adjustments

Soft clamp (schedule + no ranked wins): $$ \text{WinsScore} \leftarrow \begin{cases} 0.90 \cdot \text{WinsScore}, & \text{if } \text{RankedWins}=0 \text{ and } \overline{Q}_t < 0.55 \\ \text{WinsScore}, & \text{otherwise} \end{cases} $$

Strength-of-schedule multiplier (with average opponent quality \(\overline{Q}\)): $$ \text{SOS}(\overline{Q}) = 0.50 + 1.10 \cdot \overline{Q}. $$

Diminishing returns on unranked wins (starting after the first): $$ d(n) = 0.93^{\max(0,\,n-1)}. $$

Ranked-win additive kicker (scaled by ranked-opponent quality): $$ \text{Kicker} = \kappa \cdot \text{RankedWins} \cdot \bigl(0.7 + 0.3\,\overline{Q}_{\text{ranked}}\bigr), \quad \kappa=0.30. $$

Final Score

$$ \text{WinsScore}(t) = \Bigl(\sum_{g \in \text{games}(t)} \text{value}_g\Bigr)\cdot \text{SOS}\!\left(\overline{Q}_{t}\right)\cdot d\!\left(\text{UnrankedWins}_{t}\right) + \text{Kicker}. $$


Algorithm Design (Step-By-Step)

  1. Data: Pull FBS games for weeks 1..W; duplicate rows home/away with result, location, margin.
  2. Week-specific Coaches Poll: For each week, map team → \(Q\) and rank → \(rq\).
  3. Fallbacks: If no poll for opponent that week, use normalized SRS; else shrunk win% through week.
  4. Per-game scoring: Apply equations above; special handling for unranked P4 vs G5/Ind.
  5. Season aggregation: Sum game values; multiply by SOS; apply unranked-win decay; add ranked-win kicker.
  6. Ranking: Sort by WinsScore (tie-break by tougher average opponent quality).

My current rankings going into week 8:

This table contains the latest Top-25 output from the model after week 7.

#TeamWinsScoreAvgOppQRanked WinsUnranked Wins
1Indiana8.9612480.68589423
2Ohio State8.5768600.62928323
3Alabama7.4826680.52247032
4Miami7.3687110.48098831
5Texas A&M6.5622950.60800115
6Ole Miss5.7351840.55312815
7Georgia Tech5.5672080.52625214
8LSU5.2900030.64100613
9Oregon4.9324830.52516913
10Texas Tech4.2943250.41360714
11Virginia4.0700620.53719213
12BYU3.9357610.52391305
13Cincinnati3.9093350.56157413
14Georgia3.8822460.49460013
15Vanderbilt3.5148940.44232513
16USC3.2724740.33423414
17South Florida3.2610100.39449922
18Tennessee3.2006760.57872704
19Illinois3.0393740.52363913
20Oklahoma2.9626970.29344422
21Utah2.9443160.34758813
22Washington2.8819420.62029004
23Notre Dame2.5376560.56183404
24Tulane2.3206230.48899305
25Nebraska2.2991560.43040404

Reproducibility

Parameters (Current)