Back to work

Case study / SPORTS ANALYTICS

Football Tactical Metrics

Player-tracking data in, validated tactical and physical metrics out — a source-agnostic pipeline that unifies two tracking providers behind one schema, then computes and validates defensive shape, space control and player physical output.

Python 3.13kloppypandasSciPyShapelymplsoccerStreamlitpytest

Architecture

Metrica /SkillCornerUnified schemaMetrics layerValidationDashboardCoverage rule≥95% tracked, or the value stays empty

How it works

01

Ingest

Metrica and SkillCorner tracking data — x/y positions for every player and the ball, 10–25 times a second — are parsed through kloppy into one unified schema.

02

Unify

The metrics layer never knows which provider a frame came from; even whether a player’s distance is reported is decided by tracking coverage, not by data source.

03

Compute

Tactical metrics (defensive line height, width, compactness, Voronoi space control, pressing) and physical metrics (distance, high-speed running, sprints) are derived from configs/metrics.yaml thresholds — never hardcoded.

04

Validate

Every metric is checked against synthetic ground truth with known answers (e.g. a straight line at 5 m/s for 10 s must return exactly 50.0 m) plus real-data checks reported rather than tuned away.

05

Serve

A Streamlit dashboard renders the Voronoi pitch-control diagram and centroid paths from precomputed files — no live model behind it, by design.

Engineering highlights

168 of 190 validation checks pass; 22/22 synthetic ground-truth checks pass exactly

Coverage rule: physical totals are only reported for players tracked ≥95% of the match — others get a below_coverage flag, not a misleading number

Glitch-aware speed pipeline: Savitzky-Golay smoothing with jump detection removes single-frame tracking spikes before differentiating speed

Next project

SmartIngest →