Notes & Working Papers
2026.07.29
v1.0

444 Matches of Free Football Data

I went looking for the numbers behind the World Cup commentary, found StatsBomb's open data, and spent a few weeks poking around in it. Here is what's in there, what you can actually measure, and what I want to test next.

AuthorROME THORSTENSON
FiledJULY 2026
Reading9 min
StatusDRAFT
A dark, floodlit football pitch on which 1,172 thin glowing lines — one for every goal in StatsBomb's open Premier League 2015/16 and Women's World Cup 2023 data — fan out from across the attacking third and converge on a single blazing goal mouth.
Fig 0.0 Every goal in 444 matches of open data, traced strike to net.

I watched a lot of football this summer. Somewhere around the third time a commentator said a team "controlled the game without the ball," I started wondering where any of these numbers come from. Expected goals, PPDA, progressive passes — pundits throw them around like they're readings off a dial. Is there actually a dial? Can I look at it?

Turns out: sort of. StatsBomb publishes a chunk of their event data for free on GitHub, with documentation and no login. I pulled it down expecting a toy sample. Instead I got whole seasons.

So of course I had some agents load it into DuckDB and started poking around.

§ 01 Corpus

What's actually in the box

The download gave me 444 matches from two competitions.

The Premier League 2015/16 season has all 380 matches as event data. Every pass, shot, pressure, lineup, and substitution, logged with coordinates and outcomes — 368,619 passes and 9,908 shots across the season. What it doesn't have is any record of where the other players were standing.

The Women's World Cup 2023 has 64 matches with that same event data plus 360 freeze frames: at the instant of each on-ball event, the recorded position of every player on the pitch. That's 2.8 million freeze-frame rows.

One competition tells you what happened to the ball. The other also tells you where all twenty-two players were when it happened.

§ 02 Metrics

What you can measure

With event data alone — so, both competitions — you can measure how a team defends and attacks without knowing a single off-ball position.

MetricTableDetail
PPDA, block height, regain speedopponent_defensive_behavior_featuresHow high a team engages and how quickly it wins the ball back
Possession share, directness, progressive-pass shareteam_attacking_strategy_features888 rows, one per team per match
Pressing and counter-pressing countspressures139,845 pressure events; 29,346 flagged counterpress, the immediate press within five seconds of losing the ball
Four moments as a state machinestates, state_aggregates154,896 labeled intervals, 54,779 tagged organized-attack
Expected-threat value surfacext_gridA 12×8 grid over the pitch, fit from the outcomes in this same data

I didn't expect counter-pressing to be a literal boolean column, but it is.

The 360 freeze frames — Women's World Cup only — let me get at the off-ball geometry.

MetricTableDetail
Numerical superiority in a zonefree_man_eventsbuildup_superiority and box_superiority per in-possession event
The free-man detectorfree_man_eventsA teammate counts as free when no opponent is inside a radius and the passing corridor to them is clean
Pitch control, zone of influencefreeze_framesWhose territory each patch is, inferred from position alone since the frames carry no velocity
Ball-referenced compactnessfreeze_framesBuildable; not yet built

The first time the free-man query returned rows, I checked it twice.

Compactness tripped me up. A convex-hull spread of the defending team is a two-line computation, and I built it before I understood what I was measuring. Then I read what coaches mean by a compact block: it's ball-referenced, condensed toward where the ball is, not merely small in area overall.

Computed compactness versus what a coach means by compact Two mini-pitches showing the same players. Left: a convex hull drawn around all of them, a large symmetric shape that ignores the ball entirely. Right: the same players, but only the ones condensed toward the ball count as compact; a tight hull hugs the ball-side cluster while three far-side players sit outside it, pale, uncounted. COMPUTED — CONVEX HULL MEANT — CONDENSED TOWARD THE BALL ball one hull, wherever the ball is width × length, averaged over the match ball far side tight hull, hugging the ball far-side players deliberately not counted
Fig. 1 Same players, two different shapes. Left: the convex hull a spreadsheet computes — one number per match, symmetric, with no reference to where the ball is. Right: what a coach means by compact — a shape that shrinks and shifts toward the ball, leaving the far side open on purpose. A team can have a small hull and still be badly compact, or a large hull and be perfectly ball-side compact; the two numbers can move in opposite directions.
§ 03 Figures

Making it visible

I didn't grasp how lopsided the two data tiers were until I put them side by side.

Event row versus 360 freeze frame Two schematic pitches. Left: an event row carries only the ball and the two players it names — a passer, a recipient, and the pass between them. Right: the same instant as a 360 freeze frame, showing the recorded position of all twenty-two players, teammates as filled dots, opponents as open dots, the two goalkeepers ringed. EVENT ROW — BOTH COMPETITIONS 360 FREEZE FRAME — WWC 2023 ONLY passer recipient the ball and the two players it names start_x, start_y → end_x, end_y · outcome the same instant, all 22 positions 2.8M freeze-frame rows · 64 matches teammate opponent keeper ball
Fig. 2 What each data tier carries. An event row (left) records the ball and the two players a pass names — coordinates, outcome, passer, recipient — and nothing about the other eighteen. A 360 freeze frame (right) adds the recorded position of all twenty-two players at that same instant, which is the only thing that makes numerical superiority, the free man, or pitch control measurable at all. The catch is coverage: event rows exist for both competitions, freeze frames only for the 64 Women's World Cup matches. Positions here are schematic, drawn to show the contrast, not read from one specific frame.

The value surface was where this stopped feeling like database housekeeping. Score every action by expected threat, bin it over the pitch, and a season of Premier League football turns into a picture of where the game is dangerous.

A rendered pitch showing a smooth, Gaussian-blurred expected-threat heatmap over the 2015/16 Premier League season, brightest inside the penalty box.
Fig. 3 Value, smoothed and rendered. Every pass and shot in the 2015/16 Premier League season, scored by the expected-threat surface fit from this data, binned on a 60×40 grid and Gaussian-smoothed. Attack runs left to right. Value sits near zero across the defensive and middle thirds and climbs steeply on the approach to goal, peaking inside the penalty area — the half-space channels either side of the box read as the brightest routes in, which is where league-wide chance creation concentrates.

I kept forgetting which metrics ran on all 444 matches and which were stuck on the 64, so I drew myself a menu.

The metrics menu, split by data tier Two columns. Left, metrics computable from event data alone on both competitions: PPDA and block height, attacking-strategy features, pressing and counter-pressing counts, the four-moments state machine, and the expected-threat value surface — each tagged with its warehouse table. Right, metrics needing 360 freeze frames from the Women's World Cup only: numerical superiority, the free-man detector, pitch control, and a flagged note that ball-referenced compactness is buildable but not yet built. WHAT THIS DATA MEASURES — TWO TIERS BY DATA TYPE FROM EVENT DATA ALONE both competitions · 444 matches FROM 360 FREEZE-FRAMES WWC 2023 only · 64 matches · 2.8M rows PPDA · block height · regain speed opponent_defensive_behavior_features possession · directness · progressive passes team_attacking_strategy_features pressing & counter-pressing counts pressures.counterpress · 29,346 of 139,845 four moments as a state machine states · state_aggregates · 154,896 intervals coarse xT value surface (12×8) xt_grid numerical superiority in a zone free_man_events.buildup_superiority the free-man detector free_man_events · free within r, clean corridor pitch control · zone of influence freeze_frames · whose territory each patch is ball-referenced compactness freeze_frames · buildable, not yet built A convex-hull spread measures average player-to-player spacing — symmetric, ball-agnostic. See Fig. 1.
Fig. 4 The metrics menu. Left column: what event data alone supports, so it runs on all 444 matches. Right column: what needs the 360 freeze frames, so it runs on the 64 Women's World Cup matches only. Each box names the table it comes from.

I was slower to understand that events aren't independent rows. They chain into possessions, possessions roll up into the four moments, and every value metric above is reading that chain rather than the individual event.

From raw events to possessions to the four moments A time axis of event markers left to right: three opponent passes while the team is in organized defense, then a regain that flips possession and opens an attacking-transition window, then three quick forward passes, then organized-attack circulation ending in a shot. Below the events, three state bands label the phases; a bracket over the final four events marks the downstream expected-threat window used by the free-man test. FROM RAW EVENTS TO POSSESSIONS TO THE FOUR MOMENTS downstream xT = this action + next 3 regain shot organized defense attacking transition window T organized attack match time → 154,896 state intervals · 54,779 organized-attack opponent event our event regain shot
Fig. 5 The sequence structure the metrics read. Raw events run along the time axis; a regain flips possession and opens an attacking-transition window of length T, after which play settles into organized attack. The state machine labels every such interval — 154,896 across the corpus — and value metrics read a downstream window off the sequence, the way the free-man test scores each buildup event by the expected threat of that action plus the next three. This is why the data is more than a pile of passes: the order carries the meaning.

Next I pulled a single freeze frame from the World Cup data. What does 360 actually buy? Give every player the grass they'd reach first, and a still image turns into territory.

A broadcast-style pitch-control render from a real Women's World Cup 2023 freeze-frame, showing Philippines packed into their own box in blue and Norway's control in red just outside it.
Fig. 6 One freeze-frame, rendered as territory. A single real 360 freeze-frame from Norway's 6-0 win over the Philippines (WWC 2023) — 19 tracked players, 8 Norway and 11 Philippines — at the moment of a Norway shot. Each player spreads a Gaussian influence; every point on the pitch tints toward whichever side's summed influence dominates there, fading to turf far from any player. Eleven Philippines players are packed into and around their own box, holding the deep blue control of the penalty area, while Norway's red control owns the space just outside it — the shooter takes the shot from a red pocket at the edge of a heavily defended box.

This last one was the most fun to make, especially the little knot near the start that looks like a rendering glitch but isn't. It's the possession structure from Fig. 5 again, but drawn from a real ball trail instead of a schematic — a whole passage of play flattened into one image.

A ghosted possession trail from a real Norway buildup, a smooth curve sweeping from their own box to just outside the Philippines box, fading from amber to white.
Fig. 7 A whole possession, one frame. One real Norway possession composited into a single image: eleven completed passes starting inside their own box, ending just outside the Philippines box where the twelfth ball goes incomplete. The trail is a centripetal Catmull-Rom curve through every touch, fading from faint amber at the first pass to bright white at the last. The small tangle near the start is real — Norway circulating tightly in their own half before the ball breaks forward — not a rendering artifact; what follows is one continuous sweep the length of the pitch. This is the shape a static passing-network diagram, which draws edges but drops their order, cannot show.
§ 04 Questions

What the tables actually say

Pictures are fun. They don't settle an argument. Most of the claims I hear on broadcasts are testable against these tables, so I tested them. Each one gets a null, then what the data actually shows.

§ 04.1Pressing and transitions

Is the transition really the most dangerous moment? Coaches and commentators treat the attacking transition as the phase to exploit. state_aggregates carries expected goals and seconds per state, so I compare expected-goals-per-second in attacking_transition against organized_attack across 888 team-matches. Null: the two rates are equal, and transition looks dangerous only because it tends to happen near the opponent's goal, not because it's transition. Result: the opposite. Organized attack produces 2.49 xG per 90 seconds of its own game time; attacking transition produces 1.47 — about six-tenths as much (paired t-test across team-matches, p < 0.001). Transition still beats either defensive state by more than an order of magnitude Fig. 8, so the broadcast instinct isn't crazy — it's just being measured against the wrong baseline. Held to keeping the ball in a settled attack, transition loses.

Expected goals per 90 seconds of phase time, by state A four-bar chart. Organized defense and defensive transition are both near zero. Attacking transition reaches 1.47 expected goals per 90 seconds. Organized attack, the tallest bar, reaches 2.49 — well above transition, not below it. EXPECTED GOALS PER 90 SECONDS OF PHASE TIME 0.07 organized defense 0.05 defensive transition 1.47 attacking transition 2.49 organized attack 888 team-matches · pooled xG ÷ pooled seconds, per state
Fig. 8 Organized attack outproduces transition. Pooled across every team-match, organized attack generates 2.49 expected goals per 90 seconds of its own game time; attacking transition generates 1.47 — about six-tenths as much. Transition still beats either defensive state by more than an order of magnitude, so it isn't a non-event. It's just not the most dangerous phase on the pitch; keeping the ball in a settled attack is.

Does pressing higher actually shorten the opponent's next possession? I join pressures — using start_x for pressing height — to the following possession in passes, matched by match and possession number. Null: pressing height is uncorrelated with how long, and how far up the pitch, the opponent's next possession runs. Result: barely. Across 53,990 matched possession pairs, press height correlates with the next possession's duration at r = 0.06 and with how far it progresses at r = 0.02 — both technically distinguishable from zero at this sample size, neither large enough to act on. If anything, the most aggressive fifth of presses precede slightly longer opposition possessions (15.1 seconds) than the least aggressive fifth (12.3 seconds). This is event data, so it runs on both competitions; the null effectively holds.

§ 04.2What actually creates chances

Do wide final-third entries produce better chances than central ones? team_attacking_strategy_features splits final_third_entries from wide_final_third_entries; I join that to shots and compare xG per entry. Null: wide and central entries generate the same shot volume and quality. Result: the null holds. Wide-entry share and xG-per-entry are uncorrelated within noise (r = 0.035, p = 0.29) across 886 team-matches — the most central third produces 0.0214 xG per final-third entry, the most wide third produces 0.0231. The route in doesn't reliably predict the payoff; whatever gets a team into the box matters more than which side it comes from.

Is finishing worse under pressure, or just rarer? This one nags at me. Commentators assert it constantly, but it sounds like two different claims wearing one sentence. I mark a shot as pressured if any opposing pressures event lands in the same possession, then compare actual conversion of pressured versus unpressured shots at matched statsbomb_xg. Null: once xG is matched, pressure lowers shot count but not conversion. Result: a small real effect, not a dramatic one. Weighted across five xG bins, pressured shots convert about 0.6 percentage points worse than unpressured shots at the same chance quality. The raw gap — 9.2% pressured, 9.7% unpressured, out of 13,582 shots — doesn't clear a chi-square test on its own (p = 0.29); the effect only shows up once quality is held fixed. Pressure costs a finisher something. It's a smaller something than the commentary implies.

Does progressive passing add anything beyond simply having the ball? team_attacking_strategy_features holds both possession_share and progressive_pass_share; I regress match xG-difference on progressive share with possession share already in the model. Null: progressive-pass share adds no predictive value once possession volume is controlled — it's a restatement of having the ball. Result: mostly the null, with a crack in it. Possession share alone explains 21.9% of the variance in match xG-difference across 888 team-matches; adding progressive-pass share moves that to 22.2% — a small bump, not a rounding error but not much of one either. The raw correlation between progressive share and xG-difference is real and clears significance on its own (r = 0.13, p < 0.001), stronger than the model-based bump alone suggests, but possession still absorbs most of it. Moving the ball forward adds a little beyond simply holding it. Not nothing, but not much.

§ 04.3What the 360 data can settle

Does local numerical superiority in buildup convert to progression? This is different from the free man — it's just raw overload. free_man_events carries buildup_superiority and downstream_xt; I bucket events by superiority and compare mean downstream value. Null: buildup superiority is uncorrelated with progression, and bodies alone don't help without the free man the superiority is supposed to create. Result: it depends on how much superiority. The straight-line correlation across all 89,139 events is negligible (r = 0.004, not significant) — because the real relationship isn't a line. Mean downstream value dips slightly negative at a one-body deficit, climbs through parity and a one- or two-body advantage, then falls back at the largest three-body overloads Fig. 9. A small overload helps. A total mismatch, on this data, doesn't help more.

Downstream expected threat by buildup numerical superiority A diverging bar chart, six bars for buildup superiority from minus two to plus three bodies. The bar at minus one dips below the zero line. Bars at zero, plus one and plus two climb steadily above it, plus two the tallest. The bar at plus three falls back down, well below plus two. DOWNSTREAM EXPECTED THREAT, BY BUILDUP NUMERICAL SUPERIORITY +0.34 −2 −0.45 −1 +0.48 0 +0.77 +1 +0.88 +2 +0.18 +3 teammates minus opponents in the buildup third · xT ×10⁻³ · 89,139 events
Fig. 9 A small overload helps. A total mismatch doesn't help more. Mean downstream expected threat by buildup superiority: negative at a one-body deficit, positive from parity onward, peaking at a two-body advantage — then falling back at the largest three-body overloads. The straight-line correlation across all 89,139 events is negligible (r = 0.004) precisely because the real relationship isn't a line.

Does a ball-referenced compactness predict ball recovery where hull compactness does not? The compactness mistake left me with a better test. I build the ball-side measure — mean opponent distance to the ball — from freeze_frames, put it and a plain convex-hull area up against the same question, and check whether the defending team regains the ball within eight seconds. Null: the ball-referenced version predicts regains no better than the naive hull, which would make the distinction conceptual but empirically useless here. Result: neither version wins cleanly. Mean distance-to-ball is essentially uncorrelated with recovery (r = -0.004, not significant), though the tightest ball-side third of events does recover slightly more often than the loosest (22.3% versus 17.3%). The naive hull area, of all things, shows a small but real positive correlation with recovery (r = 0.05, p < 0.001) — bigger hulls recover more, the opposite of what either version of "compact defense" would predict. Eight seconds and a single 2D freeze frame with no velocity is a rough stand-in for "won the ball back"; I don't trust this test enough to call it settled, but the coach's version didn't obviously beat the spreadsheet's.

And then there's the free man: a teammate with no opponent inside a radius and a clean corridor to receive. free_man_events already carries reached_free_man alongside downstream_xt, so I compare the two directly. Null: reaching a free man doesn't raise the value of what follows beyond what the buildup was already generating. Result: it does, by a wide margin. Events that reach a free man produce 0.00105 downstream xT on average; events that don't produce 0.00029 — better than three times as much (t = 4.31, p < 0.001, 89,139 events). It's the one metric in this whole pile that came straight out of coaching language, and it's also the cleanest result in the batch.

§ 04.4What happens with a man advantage

Does losing a player actually change the game, or just the scoreline? Seven dismissals turn up in the lineup data across all 444 matches — three straight reds, four second yellows — each one marking the exact minute a team drops to ten. I split each match's passes and shots at that minute and compare the sent-off team's own numbers before and after. Null: a one-player disadvantage doesn't show up in territory or output at this sample size — seven matches is closer to seven case studies than a dataset. Result: small sample, mostly consistent direction. Pass share falls in six of the seven matches Fig. 10, from an average 41% of match passes before the card to 25% after — the cleanest and most consistent of the numbers here. Shot output falls in five of seven. Expected goals conceded per 90 minutes rises in four of the six chartable cases; the other two were already conceding at an elevated rate before their card, so a one-man disadvantage isn't the whole story for them. Seven cases will not settle this, but the territory loss is the closest thing to a universal finding in the batch.

Pass share and expected goals conceded, before and after a red card Two dumbbell charts sharing six team-name rows. Left: share of match passes, a grey dot before the dismissal and an accent dot after, connected by a line; the accent dot sits left of the grey dot in every row, so pass share drops after the card in all six cases. Right: expected goals conceded per 90 minutes, before and after; four of six rows show the accent dot to the right of the grey dot, meaning goals conceded accelerated, while two show the opposite. SHARE OF MATCH PASSES XG CONCEDED PER 90 0% 50% 100% 0 2.5 5 China PR Women's 27th minute vs Haiti — the example Arsenal Leicester City Nigeria Women's Philippines Women's Jamaica Women's before card after card
Fig. 10 Down a man, down the ball, mostly down more goals. Six of the seven red cards and second yellows in the corpus with a usable "after" window (a seventh arrived in the 97th minute of an already-decided match, too late to measure, and its expected-goals rate is skewed by a near-zero denominator). Pass share falls in all six — from an average 41% of match passes before the card to 25% after. Expected goals conceded per 90 rises in four of six; Nigeria and the Philippines are the exceptions, both already conceding at an elevated rate before their card. China PR Women's is the cleanest single case: sent off in the 27th minute against Haiti, their pass share falls from 70% to 44% over the rest of the match.

Every one of these is a read-only query against a single file on my laptop. The data to check what pundits say has been public this whole time. Mostly nobody checks.