Build-up & Directness

Per-team-season aggregates describing how teams move the ball forward. The standing pass-accuracy number on the team-stats pages can't tell the difference between a possession side knocking it sideways accurately and a direct side hitting completed long balls — both score high on accuracy. The build-up page splits the question into long-ball share, forward-zone pass share, and a per-match own-to-opposition long-pass rate.

Expected Points (xPts)

For every regular-season match, derive each team's win, draw, and loss probability from the pre-match Elo ratings, then convert that into expected points using the standard `3 * P(win) + 1 * P(draw)`. Sum across a season to get an xPts total per team. Compare to actual league points to surface over- and under-performers.

Game State

Every other team analytic on the site collapses a season into a single average (PPG, xPts, SQI, Elo). Game state is the opposite: it slices each season by *when* goals happen and the resulting score state. The page at `/analysis/game-state` answers:

Match Outcome Model

A multinomial logistic regression that predicts a probability for each of `away win`, `draw`, `home win` for every CPL regular-season match. The model is trained once from a frozen training split, exported as JSON coefficients, and applied to every historical match plus every new match as it lands.

Player Archetype Map

A league-wide 2D scatter that places every player-season near other player-seasons with similar profiles. The page at `/analysis/players/map` is the inverse of the player similarity feature: similarity answers "who is like X", the archetype map answers "where does X sit in the whole league". KMeans clusters running on top of the embedding give each region a short label so an unfamiliar viewer has something to read alongside the dots.

Player Percentile Rankings

For each season, rank every player's per-90 and advanced metrics against their *cohort*. Cohorts are role-based, derived from `formationPlace` in match-event data and (for midfielders) from clustering of pass-1 percentile vectors:

Player Similarity

For every qualified player-season, rank the 10 most similar other player-seasons within the same position cohort, using cosine similarity on the percentile vector. Cohorts are cross-season: a 2025 Forward is matched against every other Forward from 2019 onward, including their own earlier seasons. Matches surface on individual player profile pages as a clickable table; selecting a match overlays their percentile rankings on the current player's bars.

Playoffs

Most analytic surfaces on the site silently exclude playoff matches at the compute layer (form, splits, xPts, SQI, predictions, standings) so that derived metrics aren't distorted by tiny post-season samples. Elo, by contrast, walks every match including playoffs. The result is that pre-this-feature, the only place a user could see playoff performance was the per-match pages and a "PO" badge on match cards.

Pressing

Per-team-season aggregates of where each team wins the ball back. The team style profiling on `/analysis/style` already exposes a z-scored "pressing" dimension, but a z-score hides the denominator and conflates two different questions: *where* did you win it back vs *how often*. The pressing page surfaces both: the share split (att / mid / def of total recoveries) plus per-match volume.

Set Pieces & Corners

Per-team-season aggregates describing set-piece attack share, free-kick outcomes, corner delivery quality, and overall big-chance conversion. Everything is a sum over regular-season team-matches of fields already present in `match_stats.stats_json`. No ingest changes and no model fitting: the page exists because the underlying teamstats feed carries these numbers and nothing in the UI was surfacing them.

Shot Quality

**Shot Quality (SQI) is not xG.** It is a Poisson regression that maps a team's per-match shot-bucket counts to an expected goal total, fit on historical CPL matches. It lives at `/analysis/shot-quality` as a team-season over/underperformance table: actual goals vs SQI-expected goals, sorted by Δ. The per-match SQI values also feed [SQI Expected Points](/methods/sqi_expected_points), which converts each match's SQI pair into win/draw/loss probabilities — the principled successor to the threshold-based SQI standings on the same page.

Shot-Quality Expected Points (SQI xPts)

A second, independent expected-points model. Where [Expected Points (xPts)](/methods/expected_points) asks "how many points should a team of this *strength* have?", SQI xPts asks "how many points did the *chances this team created and conceded* deserve?" For every regular-season match, both sides' per-match [Shot Quality Index](/methods/shot_quality) values (each already a goals-scale expected-goals number) are fed into an independent double-Poisson goals model, the win/draw/loss probabilities are read off the joint distribution, and expected points follow as `3 * P(win) + 1 * P(draw)`.

Team Elo

Elo is a rolling team strength rating updated after every match. Each team enters its first ever appearance in CPL at a baseline of **1500**, gains rating for results better than expected, and loses rating for results worse than expected, where "expected" is set by the rating gap between the two sides plus a home-field bonus. The rating is zero-sum within a match (whatever one side gains, the other loses) so the league average drifts only when teams enter or leave the league.

Team Form (rolling PPG)

A trailing **7-match rolling average of points-per-game** computed per team, per season, in chronological order. Each match earns **W=3, D=1, L=0**, and the rolling-form value at matchday N is the average points across the seven most recent matches up to and including N. Early-season points use a partial window (matchday 3 averages the three matches played so far, etc.) and the `window_size` is reported alongside every point so the UI can render the "still warming up" segment differently.

Team Style Profiles

All other analysis pages answer "how good is this team?" (Elo, xPts, SQI). Style profiles answer "what kind of team is this?" by building per-team-season style vectors from ~20 stored-but-unused stats that describe *how* a team plays rather than how well they perform.

xPts Δ Attribution

The Performance vs Expectation view (`/analysis/expected`) ranks teams by Δ, the gap between actual points and Elo-derived expected points. Δ is one number with no explanation: a team can be at +6 from clinical finishing, clutch comebacks, or just luck, and the table doesn't say which.