If you met an Italian guy he will talk you about three main topic:
- Food
- Politics
- 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]
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]
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]
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:
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
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
for row in dataset.iterrows():
media.append(row["Fattore Fantahack"]/row["Qt. I"])
dataset["Rapporto Fattore Quota"] = media
Finally we can get the players that we should buy to get the ones with potentially highest score but lower price:
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)
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]
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)
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)