DEV Community

Cover image for How I tried hacking Fantasy Football using Python
adc
adc

Posted on • Edited on

How I tried hacking Fantasy Football using Python

If you met an Italian guy he will talk you about three main topic:

  1. Food
  2. Politics
  3. Fantacalcio

Now, if you're not blessed with the innate understanding of all things Italian, "fantacalcio" might sound like some exotic pasta dish or a particularly aggressive form of folk dance. Let me enlighten you. "Fanta" translates to "fantasy," and "calcio" is simply "soccer." Combine them, and you get "fantasoccer." Catchy, right?

We go totally crazy with soccer, it’s a national obsession, as far as Americans are do the same with football so, like Americans, before the starts of the Italian Championship we decide to organize an "analogic" role game, called "fantacalcio" that's quite similar to American Fantasy Football.

Imagine a group of fully-grown adults, on the first of September, congregating with the gravitas of a D&D campaign kickoff. But instead of arcane spells and enchanted swords, our weapons are... professional football players. That's fantacalcio.

Despite years playing fantacalcio is still funny for me but, in the last years, I decided to make it funnier combining it with Python.

Our dads used to play writing bought players and result using pen and paper but we're tech (not anymore so) young guy! So we uses the most popular fantacalcio service provider called, I'm not kidding, "Fantacalcio", formerly known as "Fantagazzetta".

Fantagazzetta is a cool website, it's not cool 'cause everyone uses it, it's cool because it provide all users a couple of Excel files where you can study all players stats in past and current season:

       Id  R        Nome     Squadra  Pg    Mv    Mf  Gf  Gs  Rp  Rc  R+  R-  Ass  Amm  Esp  Au
0       3  P   RADUNOVIC      Verona   3  5.83  3.00   0   8   0   0   0   0    0    1    0   0
1       4  P  SPORTIELLO    Atalanta   6  6.17  5.33   0   5   0   0   0   0    0    0    0   0
2       5  D      ALMICI      Verona   0  0.00  0.00   0   0   0   0   0   0    0    0    0   0
3      11  D       CONTI       Milan  21  5.69  5.60   0   0   0   0   0   0    2    8    0   0
4      15  D    MASIELLO       Genoa  22  5.80  5.73   0   0   0   0   0   0    1    5    0   0
..    ... ..         ...         ...  ..   ...   ...  ..  ..  ..  ..  ..  ..  ...  ...  ...  ..
748  4950  D  DALLE MURA  Fiorentina   0  0.00  0.00   0   0   0   0   0   0    0    0    0   0
749  4951  D   PICCININI    Sassuolo   0  0.00  0.00   0   0   0   0   0   0    0    0    0   0
750  4952  D   MONTERISI       Lecce   0  0.00  0.00   0   0   0   0   0   0    0    0    0   0
751  4953  C     PALUMBO     Udinese   0  0.00  0.00   0   0   0   0   0   0    0    0    0   0
752  4954  D     CELESIA      Torino   0  0.00  0.00   0   0   0   0   0   0    0    0    0   0  

[753 rows x 17 columns]
Enter fullscreen mode Exit fullscreen mode

And then the price list. Because even in fantasy, money talks, especially when you're trying to outbid your friends for the next big goal-scorer. Higher "Qt." (quota) means a more valuable, and thus more expensive, player.

       Id  R         Nome   Squadra  Qt. A  Qt. I  Diff.
0     785  A     IMMOBILE     Lazio     43     38      5
1    2841  A     VLAHOVIC  Juventus     41     34      7
2     531  A      BERARDI  Sassuolo     38     31      7
3     608  A    ZAPATA D.  Atalanta     37     33      4
4    2764  A  MARTINEZ L.     Inter     33     32      1
..    ... ..          ...       ...    ...    ...    ...
541  5505  A   KAIO JORGE  Juventus      1      5     -4
542  2654  A        CETER  Cagliari      1      2     -1
543   532  A   FALCINELLI   Bologna      1      1      0
544  4940  A     GAGLIANO  Cagliari      1      1      0
545  5060  A      AKE' M.  Juventus      1      1      0

[546 rows x 7 columns]
Enter fullscreen mode Exit fullscreen mode

So, we have data. Lots of data. What's a self-respecting tech-junkie to do? Why, turn that data lemon into lemonade dataset, of course! (And yes, that was a terrible pun, but I'm sticking with it.)

First, I focused on the last three glorious football seasons, specifically hunting for yearly average scores (Fantamedia) and the number of games played (Partite Giocate). Any player who apparently decided Italy wasn't quite ready for their brilliance in the last three seasons? Gone.

     R         Nome   Squadra  Qt. I  Partite Giocate 2019-20  Fantamedia 2019-20  Partite Giocate 2020-21  Fantamedia 2020-21  Partite Giocate 2021-22  Fantamedia 2021-22
0    A     IMMOBILE     Lazio     38                       37                9.49                       22                8.05                       19                9.03
1    A     VLAHOVIC  Juventus     34                       27                6.46                       22                7.32                       21                8.88
2    A      BERARDI  Sassuolo     31                       31                7.85                       18                7.94                       20                8.42
3    A    ZAPATA D.  Atalanta     33                       28                8.66                       23                7.72                       16                8.50
4    A  MARTINEZ L.     Inter     32                       35                7.29                       23                8.39                       18                7.89
..  ..          ...       ...    ...                      ...                 ...                      ...                 ...                      ...                 ...
293  C      PALUMBO  Juventus      1                        0                0.00                        1                5.00                        0                0.00
294  C     KINGSLEY   Bologna      1                        1                6.00                        0                0.00                        2                5.50
295  A        EDERA    Torino      3                        9                5.83                        2                6.50                        0                0.00
296  A  NESTOROVSKI   Udinese      9                       21                6.24                       14                6.28                        0                0.00
297  A     GAGLIANO  Cagliari      1                        1               11.50                        0                0.00                        0                0.00

[298 rows x 10 columns]
Enter fullscreen mode Exit fullscreen mode

With these data I code a little algorithm trying to get the value "Fattore Fantahack" that will display players with better performance in last years:

FantaHack

Quite easy to be Pathonyzed:

for row in dataset.iterrows():
    if  row['Partite Giocate ' + years[0]] > 0:  
        fattore_fantahack = (row['Partite Giocate ' + years[0]]/38 * row['Fantamedia ' + years[0]])*0.20 + 
            (row['Partite Giocate ' + years[1]]/38 * row['Fantamedia ' + years[1]])*0.60 + 
            (row['Partite Giocate ' + years[2]]/partite_giocate * row['Fantamedia ' + years[2]])*1.20 
Enter fullscreen mode Exit fullscreen mode

And finally, the grand reveal! The players we should be buying, the hidden gems, the ones who promise maximum glory for minimal investment. This, my friends, is "Convenienza" – literally, "Convenience," but in a fantacalcio context

Rapporto FQ

for row in dataset.iterrows():
    media.append(row["Fattore Fantahack"]/row["Qt. I"])
dataset["Rapporto Fattore Quota"] = media
Enter fullscreen mode Exit fullscreen mode

Finally we can get the players that we should buy to get the ones with potentially highest score but lower price:

Convenienza

for row in dataset.iterrows():
    if  row["Fattore Fantahack"] > 0:    
        total.append((row["Fattore Fantahack"]*row["Rapporto Fattore Quota"]))
dataset["Convenienza"] = total
result = dataset.sort_values(by="Convenienza", ascending=False)
Enter fullscreen mode Exit fullscreen mode

Behold, a sneak peek at the output, sorted by our shiny new "Convenienza" metric. Naturally, the superstars will still have a higher "Fattore Fantahack" – they're superstars for a reason, even in my algorithm. But sometimes, a cheap, reliable defender can be more convenient than a flashy, overpriced striker who spends half the season injured. (Don't ask me how I know.)

     R         Nome      Squadra  Qt. I  Partite Giocate 2019-20  Fantamedia 2019-20  ...  Fantamedia 2020-21  Partite Giocate 2021-22  Fantamedia 2021-22  Fattore Fantahack  Rapporto Fattore Quota  Convenienza
56   P       OSPINA       Napoli      1                       17                5.09  ...                5.17                       19                5.55           6.121667                6.121667    37.474803        
175  C        MEDEL      Bologna      2                       23                5.65  ...                6.12                       20                5.75           6.568111                3.284056    21.570042        
176  C       DEIOLA     Cagliari      2                       10                6.05  ...                5.59                       18                6.00           6.354105                3.177053    20.187327        
88   P  TERRACCIANO   Fiorentina      1                        7                5.64  ...                0.00                       18                4.83           4.071789                4.071789    16.579470        
101  C      CATALDI        Lazio      3                       16                6.22  ...                5.62                       19                6.16           6.790409                2.263470    15.369886        
..  ..          ...          ...    ...                      ...                 ...  ...                 ...                      ...                 ...                ...                     ...          ...        
242  A         MORO        Lazio      3                        0                0.00  ...                0.00                        7                6.07           0.000000                0.000000     0.000000        
250  D  JAROSZYNSKI  Salernitana      5                        0                0.00  ...                0.00                        8                5.12           0.000000                0.000000     0.000000        
262  P       ARESTI     Cagliari      1                        0                0.00  ...                0.00                        0                0.00           0.000000                0.000000     0.000000        
264  P    MARCHETTI        Genoa      1                        0                0.00  ...                2.75                        0                0.00           0.000000                0.000000     0.000000        
219  A        OUNAS       Napoli      7                        0                0.00  ...                6.44                        5                6.10           0.000000                0.000000     0.000000

[298 rows x 13 columns]
Enter fullscreen mode Exit fullscreen mode

If you're feeling fancy you can even export this glorious, algorithmically-curated list into a shiny new Excel file, neatly organized by player role. Because nothing says "I'm a professional fantacalcio manager" like a multi-sheet spreadsheet.

# I already know I could use a list of dict or an even more pythonic way for this but I preferred using two list to make this script more readable by everyone :)
position_compact = ["P", "D", "C", "A"]
position = ["Portieri", "Difensori", "Centrocampisti", "Attaccanti"]
with pd.ExcelWriter("Fantahack.xlsx") as writer:
    for p in position_compact: result[result["R"] == p].to_excel(writer, sheet_name=position[position_compact.index(p)], index=False)
Enter fullscreen mode Exit fullscreen mode

Does it actually work, you ask? Is my Pythonic fantacalcio experiment a resounding success or a spectacular failure? Well, I'll tell you in June, when the Italian Championship finally grinds to a halt. For now, I'm second out of ten in my league, which, for a squad assembled by a cold, calculating "computer" challenging flesh-and-blood "humans," isn't too shabby :)

Top comments (0)