This is one I might regret, come May and the end of the season.
First of all, this post is about soccer football, not football football (which I don’t know the first thing about). My friends and I play the popular online Fantasy Premier League game for English soccer teams. I’m a pretty avid fan of the league, at least as Americans go—but every year, my fantasy team ends up doing much worse than my passion and intellect deserve. This year, I’m putting hard data to the test in the age-old question: Is modern data analysis really better than old-fashioned experience and human intuition?
Here’s the scoop. The Fantasy Premier League (FPL) website gives you £100.0 at the start of the season to build a roster of 15 players, 11 starters and 4 subs. Better players cost more; worse players are cheaper. Points are assigned to each player after every matchday for things like scoring goals, getting assists, keeping clean sheets, or being man of the match. The key to this game—and the “human intuition” argument—is to identify the “hidden gems,” the undervalued players ready to take the league by a storm and start banging in goals when no one expected them to.
I created two teams this year, my intuition team and my data-optimized team. Due to laziness and procrastination, both were created late: my intuition team after the first matchday and my data team after the second matchday (so the data team has some catching-up to do, already). I downloaded all of last year’s players and their final point tallies and prices, and let my optimization algorithm (see below) do the work. Then I went to China for two weeks with my family. When I got back, it was matchday 5 and I reprogrammed the algorithm to use point values amassed during the current season instead. Each week this season, I plan to run the optimization and update my data team according to its dictates; I will also maintain my intuition team as independently as I can, as a best-attempt at a control.
Interesting Results
The most interesting results on this one might have to wait until the end of the season, when I will surely post an update here. However, even my initial optimized team was strongly defender-focused, a very surprising result for me. Traditional wisdom generally favors as attacking a team as possible, with formations like 3-4-3 or 3-5-2, to maximize the team’s lucrative goals count. Yet my initial optimizations returned teams in 5-4-1 or 4-5-1 formations, highly defensive organizations. It appears that FPL assigns higher prices per point to attackers, and the real play might be to go for solid, dependable defenders. Or maybe it was just a fluke? My sample size is, after all, 1—for the time being.
My code and data can be found here. Feel free to use it.
For the Interested: How the Optimization Works
Okay, I don’t believe that this operation actually requires such a heavy-duty optimization algorithm, or maybe even any sort of optimization algorithm: you could probably achieve the same result by just calculating a points per dollar ratio for each player and choosing the top 11 that satisfy the relatively simple requirements. But where’s the fun in that? Here’s what I implemented instead.
Any optimization algorithm needs some value to optimize: to compare better vs. worse. In this case, it’s pretty simple: total points of the starting 11 players. The reason this could be a nontrivial optimization problem is because of the restrictions placed upon rosters: (1) Total cost must not exceed £100.0; (2) Roster must be comprised of 2 goalkeepers, 5 defenders, 5 midfielders, and 3 attackers; (3) No more than 3 players from the same real-life team; and (4) The starting 11 (a.k.a. the point-scoring subset of the team) must be one of 7 valid formations (e.g. you can’t play 2 defenders, 5 mids, and 3 forwards).
Checking all possible rosters for the absolute best one would require 8.4*10^26 iterations. Even at a million iterations a second, that would take over 26 trillion years to complete. This is where optimization comes in: instead of checking each possibility, start with a random roster, then swap one or more random players in the team for random new players. If the new team is better than the old one, keep the swap; otherwise, revert back to the old team. Do this a few million times, and you should get pretty close to the best possible team.
This is the basic idea behind the simplest “hill-climbing” optimization. For this project I implemented something closer to a Metropolis-coupled Markov chain Monte Carlo method (better known as MCMCMC, or MC3). There is a large and highly unnavigable body of literature on these types of optimization methods, and I am severely unqualified to represent it; however, by my understanding, MCMCMC performs this simple optimization procedure multiple times in a “chain” of parallel rosters, with varying “temperatures” or degrees of acceptance of worse outcomes. So the first roster in the chain would be the “cold” one and only ever accept swaps that yield a better team. The subsequent rosters in the chain would be progressively hotter, meaning they have higher probabilities of accepting a swap that yields a worse team. The last and hottest roster, for instance, might just be swapping completely randomly, regardless of whether each swap yields a better or worse team. Then, if ever a hotter roster has a better team than a colder one, the chain is reorganized “bucket-brigade” style and the better roster gets passed down the temperature scale.

Why do this? Having a bunch of hotter rosters to back up the cold one enables it to get out of local maxima, or positions where no single swap yields a better team (so the optimization is “stuck”), but it’s still not the overall best team it could be. By enabling varying temperatures, some rosters are allowed to “regress” a little bit from the local maximum and “restart” from a different, worse point, but which may yield better results in the end.