
Link to Previous Articles:
If you have just landed on this blogpost for the first time, please make sure to read the original blogposts that describe in more detail how we used Python to write a player recommendation algorithm that uses a Moneyball approach to select the most optimal EPL Fantasy team each week. Links below:
EPL Fantasy is one week away and our Algorithm is ready to play!
Beating the Fantasy Premier League game with Python and Data Science
What’s new this week?
We incorporated additional logic to the algorithm that allows you to dynamically update the following metrics each week to optimize the long term ROI expectations:
- Declare what team formation you want to use for the week – algorithm picks smartly to maximize budget towards selected formation. So, if you declare a 4–4–2 formation, the code will get you best 4-DF, 4-MD and 2-ST by ROI and then fill the rest of the spots with whatever you can afford with remaining budget that still maximizes ROI.
- Declare budget allocation – we can now dynamically set what % of total budget we want to spend per position. So, you can say GK = 10%, DF = 25%, MD = 40% and ST = 25%, and the algorithm will only spend $10M on GKs, $25M on DFs, $40M on MDs, and $25M on STs. This way if you decide to switch from a 5–3–2 formation to a 3–5–2, you can shift budget accordingly to spend more $$$ on offensive vs defensive players.
- Declare opponent strength – the fantasy already has an FDR stat that looks at team strength of next opponent. We took that stat and are currently looking at the AVG_opponent_strength for the next 3 games and telling our algorithm to skip picking a player if their team’s AVG_FDR ≥ 3.5. We can dynamically change the cutoff number and also control if we want to look 1, 2, 3 or more games ahead. Right now, we are using next three games because we’re trying to avoid doing too many transfers each week, so we want to make sure that when we pick a player for our team, they will have a high ROI expectation at least for the next 2–3 games before we consider transferring them or putting them on the bench.
Current Fantasy Opponent Strength Ranking:
Note that we can also update this dynamically as the season progresses and relative team strengths change. But for starters we find this ranking adequate.
('LIV', 5),
('MCI', 5),
('ARS', 4),
('CHE', 4),
('MUN', 4),
('TOT', 4),
('BOU', 3),
('BUR', 3),
('CRY', 3),
('EVE', 3),
('LEI', 3),
('NEW', 3),
('SOU', 3),
('WAT', 3),
('WHU', 3),
('WOL', 3),
('AVL', 2),
('BHA', 2),
('NOR', 2),
('SHU', 2)
Gamesweek 1 Stats:
Below you can see the TOP 10 ROI players for each position. Remember that ROI is calculated as total_points / player_cost, so you might not see some players with lots of point here if their price is too high at the moment. This will all converge within few weeks, and the more consistent, top-performing players should eventually surface towards the top of the ROI charts.
Top 10 Goalkeepers by ROI

Top 10 Defenders by ROI

Top 10 Midfielders by ROI

Top 10 Strikers by ROI

Once we accumulate a few more weeks worth of data, I plan to also include other interesting statistics, such as Top 10 Players by "total bonus points", "points_per_minutes_played" and team stats such as "Total_Team_ROI", "AVG_player_ROI_per_team" etc. so we can start identifying the "underperforming" vs. "over-performing" teams and the "underpriced" vs. "overpriced" players.
Gamesweek 2 Optimal Team Recommendation:
First we need to define our formation, budget allocation, and which teams we will not be selecting players from due to high FDR (opponent strength) score.
- Team formation: 3–4–3 formation for Week 2
- Budget allocation: GK = $10M, DF = $24M, MD = $43, ST = $23M
- Teams to exclude from player selection:
Below you can see the teams that are facing the hardest opponents on AVG during the next 3 weeks:
('Arsenal', 4.0),
('Burnley', 4.0),
('Spurs', 4.0),
('Brighton', 3.67),
('Southampton', 3.67),
('Bournemouth', 3.33),
('Liverpool', 3.33),
('Norwich', 3.33),
('Sheffield Utd', 3.33),
('Wolves', 3.33),
('Aston Villa', 3.0),
('Leicester', 3.0),
('Man City', 3.0),
('Man Utd', 3.0),
('Newcastle', 3.0),
('Watford', 3.0),
('Crystal Palace', 2.67),
('Everton', 2.67),
('Chelsea', 2.33),
('West Ham', 2.33)
According to these AVG_FDR scores, our algorithm will avoid selecting players from Arsenal, Burnley, Spurs, Brighton, and Southampton during the next 2–3 gameweeks, until AVG_FDR scores drop below 3.5.
Final Team Recommendation for GW 2:
Please note that these selections below are only based on one week worth of data, which means that a lot of these picks might be a bit premature based on temporary ROI scores that might not hold in the long run. That being said, we expect these numbers to start converging towards more accurate long term ROI expectations after at least 4–5 weeks worth of data. Until then, you might see some random player names there and not see some solid players that you would typically expect to see. Still, these initial stats can give us an idea of which players/teams are currently "running hot" and might help us find a couple of initial hidden "gems" with low prices and high ROI, which might be underpriced at the moment and gain lots of value in the long run if they keep performing consistently.

Since we cannot completely change our team each week, we will use the above recommendations and the current ROI stats to select our 1–2 substitutions for our team – "alGOALrithm" and try to optimize towards max ROI during Gameweek 2. Note that our original team selection was based on ROI stats from last season, so it will take a few weeks and stats updates to start removing some of the "underperforming" and "overpriced" players from last season and start adding some of the hotter "over-performing" and "underpriced" players of the current season.
Please feel free to reach out to us with ideas and recommendations on how we can improve this algorithm further or suggestions on other interesting stats you might want us to calculate and visualize during future blogposts.
Good Luck during GW2 to all!