(Linearly) Optimising Fantasy Premier League Teams — Part 2

Joseph O'Connor
3 min readSep 13, 2020

--

This is a series on using linear optimisation to play fantasy football. In Part 1 I showed how to formulate a linear program to perform a simplified FPL team selection. This week we will look at how to start solving the problem of making transfers for an existing team.

The code used in this post starts getting complex, so I’m going to implement a TransferOptimiser class and break down functionality into class methods. Let’s begin with a skeleton of the desired functionality.

Decisions

In this problem, we want our decisions to represent transfers in and out of a squad of players. These will look a lot like our player selection decisions — a binary decision per player corresponding to “transfer_in” and one to “transfer_out”.

There is extra complexity in that one free transfer is allowed per week, with all others incurring a points penalty. The best way to model this is with separate “free_transfer” and “paid_transfer” variables.

Constraints

First, we use the transfer decisions to calculate next week’s team

Since this is just a linear combination of our decision variables, we can apply the formation constraints from the last post directly to next_week_team, i.e.

We also require the following constraints on transfers:

  • Only one free transfer allowed per week
  • The transfer budget cannot drop below zero

Objective

This should remain similar to the static case from last week: maximise the expected number of points across the team. There is now one addition to the objective, which is the four-point penalty for additional transfers.

transfer_penalty = sum(transfer_in_decisions_paid) * 4

Putting it together

The final version of TransferOptimiser can be found here, and a notebook to run it over 2020–21 FPL data here.

First we pick a starting team based on the linear program from the last post. Since that is over a year old, here is the selected starting team for 2020–21.

Total expected score = 61.82

First Team:
Nick Pope | expected score = 4.47 | price = 5.5
Virgil van Dijk | expected score = 4.68 | price = 6.5
Andrew Robertson | expected score = 4.76 | price = 7.0
Trent Alexander-Arnold | expected score = 5.52 | price = 7.5
Matt Doherty | expected score = 4.39 | price = 6.0
Ashley Westwood | expected score = 3.10 | price = 5.5
Kevin De Bruyne* | expected score = 6.60 | price = 11.5
John Lundstram | expected score = 3.78 | price = 5.5
Anthony Martial | expected score = 5.26 | price = 9.0
Danny Ings | expected score = 5.21 | price = 8.5
Raúl Jiménez | expected score = 5.10 | price = 8.5

Subs:
Dale Stephens | expected score = 1.65 | price = 4.5
Mathew Ryan | expected score = 3.5 | price = 4.5
John Egan | expected score = 3.5 | price = 5.0
Mark Noble | expected score = 2.76 | price = 5.0

Our transfer optimiser requires us to make a forecast of each player’s score next week (Gameweek 2). I’ll explore effective ways of doing this in a later post. For now, to demonstrate the algorithm I’m going to make some simple hand predictions. Starting from the baseline forecast of last season’s points per game, I’m going to give +1 expected points to all Chelsea players and -1 expected points to all Liverpool players.

Solving this model gives one transfer:

Out: Virgil van Dijk | expected score = 3.68 | price = 6.5
In: César Azpilicueta | expected score = 4.42 | price = 6.0

Modelling only one week ahead is not very useful. In fact, common sense tells us the exact behaviour that is optimal for maximising the expected score next week.

  • Rank all legal player trades by their increase in expected score.
  • If any are greater than the four-point transfer penalty, make them.
  • If not, use your free transfer to make the most valuable trade.

The real value of this model will be in the ability to optimise transfer plans over horizons of multiple weeks, with the objective of maximising the long-run score. Given a good player score forecast, this model can make plans to shift the squad over time to accommodate easy runs of games or to save up for a high-performing player.

Extending the above model to plan over horizons of multiple weeks is pretty simple, but we’ll need to apply some tricks to make it work well. I’ll explore this in the next post.

Notebooks and code are available at https://github.com/joconnor-ml/forecasting-fantasy-football.

--

--