Solo Queue Analytics
J

Jackson Angell

Data Scientist / Engineer

Last updated 11 hours and 14 minutes ago

The next game

Right now Logistic argmax expects him to play Lulu next, at 21% confidence.

Across 427 scored games it runs at 34%, against 27% for decay frequency, the model to beat. McNemar's test puts that gap at p = 0.001, so it is performing significantly better than the baseline.

See how all six scored

The short version

I wanted to know whether I could predict my own League of Legends games. The Prediction page keeps score, including the models that lose.

Every ranked game I play comes off the Riot API into Snowflake overnight, and six models take a guess at what I'll play next. Each is scored walk-forward, trained only on games that happened before the one it's predicting. The accuracy carries a 95% confidence interval, and the gap to a baseline that does no learning at all gets a significance test. On a few hundred games, that baseline is hard to beat.

It runs itself on a nightly cron and serves from cache, so browsing never touches the warehouse. Under $10 a month.

Prediction is the part I'm proudest of: six models guessing my next ranked champion, scored against what I actually played. Statistics covers win rates, and which friends I win more with. Playstyle measures seven axes of how I play against everyone else at my rank.

Data pipeline

1

Riot Match-V5 API

Pulls any games I haven't downloaded yet.

RESTrate-limited24h key
2

Ingest

~90 stats per player; a match saves all ten or none.

Pythonrequestsidempotent upsertatomic writes
3

Snowflake warehouse

Holds every match, and what the pipeline has already done.

SnowflakeSQLkey-pair auth
4

New-game gate

Models rerun only after a new ranked game.

state tabledeterminism
5

Walk-forward models

Six guesses at my next champion, trained only on earlier games.

scikit-learnXGBoostwalk-forwardranked-only
6

Publish

Results written back in one format the site can read.

VARIANTone query shape
7

This website

Serves cached results; browsing never hits the warehouse.

FlaskChart.jsRendercached daily
Why once a night

Nothing changes between runs, so running it more often would only wake the warehouse to find that out. The cron is best effort, so a run can be delayed or skipped. The heartbeat above is how you'd know.

Stack

LayerChoice
WarehouseSnowflake, key-pair authenticated
PipelinePython, scheduled on GitHub Actions (requests, pandas, scikit-learn, XGBoost)
WebsiteFlask + gunicorn
DeploymentDocker container (slim Python base, non-root), deployed on Render
AssetsChampion art pre-fetched from Data Dragon, served as static files
AI summariesClaude API, called on demand and rate-limited per visitor