Each team's rating is the margin the model predicts it would win by against a perfectly average FBS team on a neutral field. A rating of +21 means about three touchdowns better than average. It comes from three models run in sequence, all trained on play-by-play data going back to 2000, followed by a final rating step.
Most college football analytics count a play as a success using a fixed rule, usually "gain 50% of the yards needed on 1st down, 70% on 2nd, 100% on 3rd or 4th." That rule ignores the score, the clock and field position. Here, a model decides instead: a play is a success for the offense if it did not lower the offense's chance of winning, as judged by a win-probability model trained on millions of historical plays.
The two in-game models (Stages 1 and 2) never appear in the ratings directly. They are used to measure every play, and those measurements become the features for the pre-game model that the ratings come from.
Play-by-play, schedules, scores, team lists and composite recruiting talent come from the College Football Data API. Every API response is saved to disk before it is used, so the whole pipeline can be re-run offline without hitting the rate-limited API again.
Responses are loaded into a MariaDB database with three tables: teams
(including talent), games and plays. Plays for a season are
fetched in one bulk query and grouped by game in memory.
Uncategorized, it reads the play text instead.
Hand-checked edge cases in test_domain.py cover this logic.snake_case to
camelCase partway through the API's history; every accessor reads both.
A neural network (scikit-learn MLPClassifier, ReLU, inputs scaled with
StandardScaler) predicts the chance the home team wins from the game state
at the snap. It deliberately gets no team identity, so it learns what a
situation is worth rather than which teams are good.
| Down & field | down, distance, yards to goal |
|---|---|
| Clock | seconds left in regulation (combined across quarters), overtime, start of period, end of period, two-minute warning remaining (2024+) |
| Resources | offense timeouts, defense timeouts |
| Context | score margin before the play, home team on offense, neutral site, kickoff |
It is trained on every play from 2000 onward (about 3.8 million) for each combination of two hidden layers of 8, 12, 20 or 30 units, which makes 16 networks. Held-out accuracy is about 80%.
Same 14 features and the same 16 layer sizes, but this one is an MLPRegressor
whose target is the home team's final margin. Held-out R² is about
0.63.
It exists because win probability flattens out near the extremes. A play that takes a team from 97% to 98% barely registers as a probability but can still be worth real points. The margin model measures that size.
For each season, every game's plays are run through a Stage 1 and a Stage 2 model, and each pair of consecutive plays is scored:
Raw success rates reward an easy schedule. To correct for this, every team's offense, defense and special teams are fit together in one regression, with each game weighted by its number of plays:
success_rate(team vs opp) = μ + offense[team] − defense[opp] + hfa · home special_rate(team vs opp) = μ + special[team] − special[opp] + hfa · home
Fitting all teams together means each opponent's strength is itself adjusted for that opponent's schedule. A ridge penalty (λ = 150 plays, about two games' worth) pulls teams with little data toward average, and the system can still be solved early in the season when some groups of teams have not played each other yet. The results are reported as success rates against an average opponent. Defense is reported as the share of opponent plays stopped, so higher is better for every unit.
A Simple Rating System is fit the same way on final scores:
home_margin = hfa · home + r[home] − r[away], with a lighter ridge penalty
(λ = 2). Home-field advantage is estimated rather than assumed.
For each game, the opponent's raw offensive and defensive success rates going into that game are recorded. Their average across a team's schedule is a direct measure of how hard the schedule has been.
A GradientBoostingRegressor (after a StandardScaler) predicts the
final home margin of a game before kickoff. It uses 31 features: 15 per team for the home
and away sides, plus whether the site is neutral.
| Success rate | offense, defense, special teams: raw and opponent-adjusted (6) |
|---|---|
| Explosiveness | offense, defense (2) |
| Schedule | opponents' offense quality, opponents' defense quality (2) |
| Drives | average starting field position, fumble rate, forced-fumble rate (3) |
| Strength | SRS rating, recruiting talent composite (2) |
A training row is built only from what was known before kickoff:
Every one of the 16 × 16 = 256 pairings of Stage 1 and Stage 2 networks produces a different set of features, so a separate Stage 3 model is trained for each pairing on seasons 2000 to the present. In the most recent full run, held-out R² on final margin averaged 0.35 across all 256 pairings, with the best at 0.39.
In a stricter test, the model was trained only on seasons through 2022 and then predicted every FBS vs. FBS game from 2023 to 2025. It picked the winner in about 71% of those games.
An R² around 0.35 is a solid result for this problem. College football outcomes are very noisy, and the model sees only on-field performance: no injuries, weather, coaching news or betting lines.
The ratings reuse the trained Stage 3 model, but instead of a real matchup, each team is put up against a made-up average opponent:
is_neutral_site = 1.
That predicted margin is the rating. Because it is in points against a fixed opponent,
the gap between two teams' ratings is roughly the expected spread between them on a
neutral field. Results are written to team-ratings-<year>.csv, which
this site reads.
down = 0 or a
negative distance.