Champion fingerprint: how you actually play
Slice your games by champ (and champ ‘class’) to find comfort picks, traps, and patterns worth practicing.
Run after each small change. Tiny loops win.
uv run python -m src.scout data/derived/matches.csvdata/ddragon/champion_full.jsonsrc/scout/(a new report function)reports/champion_fingerprint.md
60–120 minutes
Do this (suggested order)
- Make sure Step 05 exists (
data/derived/matches.csv) and Step 01 downloadedchampion_full.json. - Read
matches.csvwith pandas and sanity printshape,dtypes, andhead(). - Load
champion_full.jsonand build a mapping from champion name → tags (like["Mage", "Assassin"]). - Pick 3 “slices” and compute them with groupby (start with: champ table, “after a loss” picks, class performance).
- Write a short markdown report to
reports/champion_fingerprint.mdwith tiny tables and 1–2 sentences per slice.
You’ll practice
- Turn one CSV into multiple “views”
- Use groupby for counts + winrates
- Join metadata (champ tags) to your dataset
Explainers (for context, not homework)
- Pandas: the minimum you need — Groupby + sort patterns
- Caching sanity — Reports are rebuildable
Build
- reports/champion_fingerprint.md with 3 slices
- Comfort picks: most played champs with winrate (min games rule)
- Tilt check: champs you pick after a loss (prev game win/loss)
- Class check: winrate by champ tag (Mage/Fighter/Support/etc.)
- Feast-or-famine: champs with highest variance in K+A or deaths
- Game length vibes: champs you pick in short vs long games
Check yourself
- Report contains at least one table with counts + winrate.
- You can point to one actionable takeaway (“I win more on X”, “I spam Y after losses”).
If it breaks
- Champion names not matching between CSV and Data Dragon
- Forgetting to sort games before using previous-game logic
- Letting one 1–0 champ look like a god (min games filter)
Hints (spoilers)
Bigger hint: the champ summary table (the one you’ll reuse forever)
Start with a table per champion: games, wins, winrate, average K/D/A. Then you can slice it 100 different ways.
Core groupby (shape, not full code)
g = df.groupby('champion')
out = g.agg(
games=('match_id', 'count'),
wins=('win', 'sum'),
kills=('kills', 'mean'),
deaths=('deaths', 'mean'),
assists=('assists', 'mean'),
).reset_index()
out['winrate'] = out['wins'] / out['games']
out = out.query('games >= 3').sort_values(['winrate', 'games'], ascending=False) Bigger hint: “after a loss” picks (a fun beginner-friendly pattern)
Sort games by time, then add a prev_win column. Now you can ask: “What champs do I lock in after a
loss?”.
Tilt-check pattern
df = df.sort_values('game_start')
df['prev_win'] = df['win'].shift(1)
after_loss = df[df['prev_win'] == False]
# then groupby champion and count Bigger hint: champ ‘class’ (tags) from champion_full.json
In championFull.json, each champion has tags like [\"Mage\", \"Assassin\"]. Join those tags to your matches so you can slice by “class”.
Tag join idea (with explode)
df['tags'] = df['champion'].map(champ_to_tags)
dft = df.explode('tags')
by_tag = dft.groupby('tags').agg(games=('match_id','count'), wins=('win','sum')).reset_index()
by_tag['winrate'] = by_tag['wins'] / by_tag['games'] Unblock-me: champ names don’t match (normalize gently)
If your CSV uses championName from match JSON, it usually matches Data Dragon keys. If you used a different
field (or renamed champs), build a tiny mapping file once and reuse it.
Unblock-me: small samples (the ‘min games’ rule)
Don’t let a champ with 1 game hijack your report. Use a filter like games >= 3 or
games >= 5 before ranking by winrate.
Expected report
reports/
champion_fingerprint.md Report skeleton (tiny, readable)
# Champion fingerprint — <Name#TAG>
## Comfort picks (min 3 games)
- ...
## After a loss (what do I pick?)
- ...
## Class check (tags)
- ...
## One takeaway
- ...