Simulated Scenarios
with
against Rival
Information - Q/A
This page shows potential outcomes for next GW (GW{{ current_gw }}) using simulation replications.
What is the purpose of it?We already have great models for optimizing FPL decisions based on expected value (EV) -- projected points. Using these models will take you a step ahead of other managers, but for practical reasons, lack some aspects. For example, having two or more players on the same team or opposite teams for a game limits how many points you can get this GW. Therefore, even for two teams with exactly same EV but with different players, shape of the outcome distribution will be different. For example, we know that captaining a differential have a big upside, as well as a risky decision, but have no way to quantify it. Unless, we simulate match outcomes and see the distribution itself.
Who needs this?If you are interested in optimization for FPL and wondering what the potential outcomes look like for your team. Note that, this page shows example outcomes for reference, but I urge you to build your own simulator if you have the means.
How do you generate simulation replications?Using the Free Model of the amazing FPLReview, I collect goal/assist/bonus rates for each player. Then, using Monte-Carlo simulation (and a bunch of assumptions), I simulate the GW over and over. Similar stats (anytime goalscoring, anytime assist, clean sheet, etc...) are also available on several websites, but not being used here.
What is included in simulations?
- Goal points
- Assist points
- Clean sheet points
- Goals conceded points
- Bonus points
- Autosub replacements
I am hoping to improve quality of simulations in future, but here are current limitations and assumptions.
- Using expected minute values, I assume a player either plays 90 mins or 0 mins. No subs.
- Bonus point logic is a bit involved, but I assume only 1 player to get 3 points, 1 player to get 2 points and 1 player to get 1 bonus point.
- I exclude events like yellow card / red card / penalty miss / penalty save.
- Current model does not consider vice-captain switch
If you are serious about optimizing your decisions for FPL, then the next step after the multi-period EV model is to use stochastic optimization. It is a better way to calculate probabilities and in general a better way to approach stochastic nature of FPL from a decision making perspective. Consider a simple case, where it is last GW of the season and you are in 2nd position OR. If you optimize over EV and get the same exact squad as the OR #1 manager, your chance of winning FPL becomes 0%. It is obvious that you need to find a player who is not owned by the top ranked manager, but have a solid EV value. Simulation, in this case for example, provide obvious benefits and can help you to calculate probability of winning. So, you can maximize probability of winning in an optimization model and increase your chance.
Is 100 replications enough?No, the more the better. But since this website is hosted on GitHub, I use GitHub actions to produce simulations every 6 hours. 100 replications is the limit I can have without increasing my webpage build time significantly. It is also a good point as mobile devices get really slow during JS calculations. If you are doing it yourself, consider having as much replications as you can for the optimization purposes.
Overview
These values are approximations based on EV values. For constructing a team, try FPLReview Planner.
Rival Team
Scenario #{{ (scenario_stats.best_one && scenario_stats.best_one.sim) || '' }}
Scenario #{{ (scenario_stats.worst_one && scenario_stats.worst_one.sim) || '' }}
Scenario #{{ (scenario_stats.best_diff && scenario_stats.best_diff.sim) || '' }}
Scenario #{{ (scenario_stats.worst_diff && scenario_stats.worst_diff.sim) || '' }}
Position | Name | Team | Price | Own% | Avg.Pts | Pts per App. |
---|---|---|---|---|---|---|
{{ element_type[player.element_type].short }} | {{ player.web_name }} | {{ teams_ordered[player.team-1].short }} | {{ (player.now_cost / 10).toFixed(1) }} | {{ player.selected_by_percent }}% | {{ sc_player_avg_full[player.id].avg }} | {{ sc_player_avg_full[player.id].pps }} |
Scenario #{{ (scenario_stats_rival.best_one && scenario_stats_rival.best_one.sim) || '' }}
Scenario #{{ (scenario_stats_rival.worst_one && scenario_stats_rival.worst_one.sim) || '' }}
Scenario #{{ (scenario_stats_rival.best_diff && scenario_stats_rival.best_diff.sim) || '' }}
Scenario #{{ (scenario_stats_rival.worst_diff && scenario_stats_rival.worst_diff.sim) || '' }}
Position | Name | Team | Price | Own% | Avg.Pts | Pts per App. |
---|---|---|---|---|---|---|
{{ element_type[player.element_type].short }} | {{ player.web_name }} | {{ teams_ordered[player.team-1].short }} | {{ (player.now_cost / 10).toFixed(1) }} | {{ player.selected_by_percent }}% | {{ sc_player_averages.avg[player.id] ? _.round(sc_player_averages.avg[player.id],1) : "-" }} | {{ sc_player_averages.pps[player.id] ? _.round(sc_player_averages.pps[player.id],1) : "-" }} |
Player Outcome
Player | Play Prob % | Average Pts | Average Pts when Play |
Min | Q1 | Median | Q3 | Max | Prob % >= Target |
---|---|---|---|---|---|---|---|---|---|
{{ v.web_name }} | {{ (v.play_prob*100).toFixed(0) }} | {{ (v.avg).toFixed(2) }} | {{ isNaN(v.avg90) ? "-" : v.avg90.toFixed(2) }} | {{ isNaN(v.q0 ) ? "-" : _.round(v.q0, 1) }} | {{ isNaN(v.q25 ) ? "-" : _.round(v.q25, 1) }} | {{ isNaN(v.q50 ) ? "-" : _.round(v.q50, 1) }} | {{ isNaN(v.q75 ) ? "-" : _.round(v.q75, 1) }} | {{ isNaN(v.q100) ? "-" : _.round(v.q100, 1) }} | {{ isNaN(v.tp) ? "-" : _.round(v.tp*100, 1) }} |
Simulations
Pos | Name | Team | £ | Own% | Points | Gain/Loss |
---|---|---|---|---|---|---|
{{ element_type[p.data.element_type].short }} | {{ p.data.web_name }} | {{ teams_ordered[p.data.team-1].short }} | {{ p.data.now_cost / 10 }} | {{ parseFloat(ownership_rate_dict[p.ID] || p.data.selected_by_percent).toFixed(1) }}% | {{ p.Points }} | {{ p.eff_points }} |
Pos | Name | Team | £ | Own% | Points | Gain/Loss |
---|---|---|---|---|---|---|
{{ element_type[p.data.element_type].short }} | {{ p.data.web_name }} | {{ teams_ordered[p.data.team-1].short }} | {{ p.data.now_cost / 10 }} | {{ p.data.selected_by_percent }}% | {{ ( current_rep_dict[p.element] && current_rep_dict[p.element].Points) || 0 }} | {{ p.eff_points }} |
Lineup Pts | {{ current_rep_values.lineup_score }} | |||||
Autosub Pts | {{ current_rep_values.autosub_score }} | |||||
Total | {{ current_rep_values.total_score }} |