Solo Queue Analytics
J

Jackson Angell

Data Scientist / Engineer

Pipeline last ran 16 hours and 32 minutes ago

The next game

Right now one of my six models, Logistic argmax, expects me to play Lulu next, at 20% confidence.

Across 429 scored games it has been right 34% of the time, against 27% for the baseline (decay frequency), which just counts what I've played lately. That lead is bigger than luck would explain (McNemar p = 0.001).

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. Each accuracy figure comes with a 95% confidence interval, and every model is tested against a baseline that does no learning at all, to check its lead isn't luck. 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: each model's next pick, and its record so far. Statistics covers win rates, and which friends I win more with. Playstyle measures seven axes of how I play, compared with other players 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 for each of the ten players; a match saves completely or not at all.

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

Picks and scores written back to Snowflake for the site to read.

VARIANTone query shape
7

This website

Serves cached results; browsing never hits the warehouse.

FlaskChart.jsRendercached daily
Why once a night

New data only arrives when I finish a ranked game, so running more often would mostly wake the warehouse to find nothing new. The cron is best effort, so a run can be delayed or skipped. The "last ran" time at the top of the page 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