Mack's LoL Scout
Stretch B

Champion fingerprint: how you actually play

Slice your games by champ (and champ ‘class’) to find comfort picks, traps, and patterns worth practicing.

Run

Run after each small change. Tiny loops win.

uv run python -m src.scout
You will touch
  • data/derived/matches.csv
  • data/ddragon/champion_full.json
  • src/scout/ (a new report function)
  • reports/champion_fingerprint.md
Time

60–120 minutes

Do this (suggested order)

  1. Make sure Step 05 exists (data/derived/matches.csv) and Step 01 downloaded champion_full.json.
  2. Read matches.csv with pandas and sanity print shape, dtypes, and head().
  3. Load champion_full.json and build a mapping from champion name → tags (like ["Mage", "Assassin"]).
  4. Pick 3 “slices” and compute them with groupby (start with: champ table, “after a loss” picks, class performance).
  5. Write a short markdown report to reports/champion_fingerprint.md with 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)

Build

Report
  • reports/champion_fingerprint.md with 3 slices
Slices (pick 3)
  • 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
- ...