Introduction
Earlier this year, I worked on a Proof-of-Concept project showcasing how you could use optimisation (yes, I’m using the British spelling!) methods on Football Tracking Data for some useful insights. This project was presented at the SkillCorner x PySport Analytics Cup 2026, with the full talk available here.
I’m happy to announce this work is now available for everyone to use as part of DataBallPy, an excellent open-source Python package for loading, synchronising, and analysing football event and tracking data. I’d like to give a huge thank you to Alexander Oonk, Joris Bekkers and Koen Vossen for their help in this endeavour, as well as the folks at Skillcorner.
With that out of the way, let’s dive into:
- My Research Question
- Where optimisation is useful
- What this repo can do
- How you can use or extend this work
My Research Question
My research goal is:
Is there a way to optimise defensive positioning, and make it understandable for a coach?
The key point here is understandability - if you have the most advanced ML algorithm but it never gets implemented, it has less impact than a crappy model which someone actually believes in. The other difficult part of this question is defining optimality - my hope is that by releasing this work to the community, we can work together to come up with interesting objective definitions of what “good” looks like for various game states.
Where optimisation is useful
I covered this topic in the youtube video linked above, but I deem it to be so important it bears repeating. For those unfamiliar, optimisation techniques are a key foundation of modern supervised Machine Learning techniques. When training ML models, they are actually just updating their parameters to minimise a loss function, such as the difference between its predictions and the actual values in its training data.
Given the research goal above, optimisation techniques are valuable because they require no training and can have human understandable objective functions. My hope is that this repo allows others to build their own optimisation algorithms against Tracking Data.
What this repo can do
The core of this repo sits around a few base classes, and specific implementations of those.
| Base Class | Job |
|---|---|
| Objective | Score a Tracking Data Frame, with higher values being “better” as we are maximising |
| Constraint | A boolean check to see if a Frame meets certain criteria, such as not moving players too far |
| Algorithm | The actual method by which we will modify a tracking frame to see if it improves an Objective whilst staying within a Constraint |
I’ll dive into the implementations of each of these below:
Objectives
Weighted pitch control
WeightedPitchControlObjective scores how much of the pitch the defending team controls over the attacking team, weighted by expected threat of the attacking team (xT), to prioritise controlling the pitch in key areas.
Higher scores mean the defence owns more of the dangerous attacking areas, i.e. are more “optimally” positioned with respect to this metric.
Pressure
PressureObjective maximises the mean pressure applied to a set of attacking players (by default, everyone on the team in possession). Pressure here uses DataBallPy’s existing player-pressure model.
Pitch control and pressure pull in slightly different directions - sitting deep can control space; stepping onto an attacker raises pressure but may leave gaps.
Constraints
Time-to-intercept constraint
TTIConstraint rejects any proposed position a player couldn’t reach from their current location and velocity within a time budget (default 1 second). The time-to-intercept model is based on theone from Devin Pleuler’s soccer analytics handbook.
Algorithms
Simulated Annealing
Simulated annealing is an optimisation technique inspired by metallurgy: heat a system, then cool it slowly so the atoms settle into a low-energy configuration.
In algorithm terms:
- Start from the current player positions
- Propose a small random move (a perturbation)
- If the move improves the objective, accept it
- If it makes things worse, still accept it with some probability, p
- Gradually reduce p so the search shifts from exploration to refinement

A sample frame with the original positions shown in red, and the optimised positions shown in a lighter colour. You can see that in order to maximise pressure and defensive control, the back 4 was stretched wider, and the attacking players were moved to press the opposition more tightly.
How you can use or extend this work
The difficulty here is defining what “good” looks like. Concretely, optimising a mix of Pressure and Weighted Pitch Control is probably not enough by itself. I would love for someone working professionally in a club or football environment to take this work and find an iterative approach to dial in the objective function.
By analysing the changes coaches would make to certain setups (e.g. by asking “Given this setup, and the fact we are 1-0 down, what would you have changed in this game?”), we would be able to glean exactly which metrics they are trying to improve, even if they cannot articulate it. From there, we could run an optimisation and see if it makes similar changes to the coach. Alternatively, we can present optimised setups and ask what weaknesses are present.
Once we have those metrics, you can use the base classes defined to extend them, for example looking to create an objective to minimise space in behind, which we can give a heavy weight to if protecting a slim lead late in the game.
Additionally, there are other inexact optimisation methods we could use, such as Particle Swarm Optimisation which could be an even better approach for this type of problem. If someone can, it would be very interesting to formulate these as LPs, as then they would have perfectly optimal solutions. Given that the variables are highly non-linear, this is not an easy task!
Next steps
A few directions I’m interested in exploring:
- Seeing if we can use this in an adversarial way to find equilibrium states - i.e. if both teams are positioning optimally relative to their objectives for a certain game state, what would the final position look like? This would allow you to monitor realistic responses by the opposition team to changes you have made, instead of assuming the opposition is static as this model currently does.
- Additional objectives such as passing-lane disruption, dangerous accessible space or attacking xT.
- Analysing set pieces to find optimal setups for different risk/reward tradeoffs.
The full docs for the code are available here.