Liga Angielska 2020/21 - Analiza Danych

Opublikowano: July 20, 2021 przez Mariusz Borycki

Photo by Nathan Rogers on Unsplash

Piłka nożna to najpopularniejsza dyscyplina sportowa z około 4 miliardami fanów na całym świecie [1].

Z kolei Liga Angielska (Premier League) to najwyższa w hierarchii klasa męskich ligowych rozgrywek piłkarskich w Anglii, będąca jednocześnie najwyższym szczeblem centralnym (I poziom ligowy).

Premier League jest obecnie (2020/21) najleszą oraz najbardziej popularną ligą na świecie [2].  

 

W związku z tym, w ramach kolejnego projektu postanowiłem przeanalizować dane z poprzedniego sezonu Ligi Angielskiej.

 

Informacje na temat analizowanych danych:

 

Kontekst:

Zestaw danych, którego użyłem jest zbiorem kluczowych statystyk dotyczących sezonu angielskiej Premier League 2020/21. Zawiera standardowe statystyki wszystkich piłkarzy, którzy grali w Lidze Angielskiej, takie jak liczba strzelonych bramek, ilość zdobytych asyst, xG (oczekiwane gole), xA (oczekiwane asysty), liczba podań, dokładność podań i wiele więcej!

 

Opis kolumn wchodzących w skład zbioru danych:

Position: każdy gracz ma określoną pozycję, na której gra regularnie. Pozycje w tym zestawie danych to FW - napastnik, MF - pomocnik, DF - defensywa, GK - bramkarz
Starts: ile razy zawodnik grał w pierwszej jedenastce
Mins: liczba minut rozegranych przez piłkarza
Goals: liczba bramek zdobytych przez piłkarza
Assists: ile razy gracz asystował innemu graczowi w zdobyciu gola
Passes_Attempted: liczba podań podejmowanych przez pikarza
PercPassesCompleted: liczba dokładnych podań do kolegi z drużyny
xG: oczekiwana liczba bramek strzelonych przez piłkarza (na mecz)
xA: oczekiwana liczba asyst zawodnika w meczu (na mecz)
Yellow_Cards: ilość żółtych kartek
Red Cards: ilość czerwonych kartek

 

Cele, czyli co w głównej mierze będę chciał zobaczyć:

  • Liczba żółtych i czerwonych kartek
  • Całkowita liczba kartek w wg narodowości
  • Liczba kartek na 1 gracza wg narodowości
  • Liczba kartek na 1 gracza wg pozycji na boisku
  • Ilość bramek i asyst
  • Zdobyte bramki - TOP 10 graczy
  • Ilość asyst - TOP 10 graczy
  • Punkty kanadyjskie - TOP 10 graczy
  • Gole według pozycji na boisku
  • Asysty według pozycji na boisku
  • Ilość niestrzelonych bramek – na podstawie współczynnika xG
  • Współczninnik oczekiwanych bramek
  • Ilość podań – TOP 10 graczy
  • Ilość dokładnych podań
  • Najstarsi gracze w Premier League
  • Najmłodsi gracze w Premier League
  • Średni wiek według pozycji na boisku
  • Średni wiek w klubach ligi angielskiej

 

Zawartość zbioru danych:

Na początek sprawdziłem co wchodzi w skład naszego zbioru daych:

 

Mariusz Borycki - firs table info

 

Jak widać, powyższa tabela zawiera 18 kolumn i 532 wierszy. 

 

 


ŻÓŁTE I CZERWONE KARTKI

Pierwszym wykresem jaki postanowiłem sprawdzić była ilość żółtych i czerwonych kartek po klubach w EPL:

 

countries = df_1.index.tolist()
red_cards = df_1['Red_Cards'].tolist()
yellow_cards = df_1['Yellow_Cards'].tolist()

width = 0.75

 

fig, ax = plt.subplots(figsize=(16, 10))

ax.bar(countries, yellow_cards, width, label='Yellow Cards', color='gold')
ax.bar(countries, red_cards, width, bottom=yellow_cards, label='Red Cards', color='orangered')

ax.set_ylabel('Amount of Cards', fontsize=14)
ax.set_title('Number of Yellow and Read Cards in Premier League (2020/21)', loc='left', fontsize=18, fontweight ='bold')
plt.xticks(countries, rotation=90, fontsize=12)

 

for index, data in enumerate(red_cards):
    plt.text(x=index , y=data + yellow_cards[index] + 1 , s=f"{data}" , fontdict=dict(fontsize=14), horizontalalignment='center')

 

for index, data in enumerate(yellow_cards):
    plt.text(x=index , y=20 , s=f"{data}" , fontdict=dict(fontsize=14), horizontalalignment='center')
    
ax.legend(fontsize=12, frameon=False)

fig.text(0.9, -0.08, 'mariuszborycki.com', fontsize = 12,
         color ='grey', ha ='right', va ='bottom',
         alpha = 0.7)

plt.show()


Mariusz Borycki - ilość kartek po klubach Premier League


Wykres został posortowany malejąco według czerwonych kartek. Można dostrzec, że Brighton jest zespołem z największą liczbą czerwonych kartek w Premier League.
Jednak najwięcej żółtych kartek i 4 czerwone kartki zdobyło Sheffield United, co przełożyło się na największą łączną ilość kartek w całej lidze.

 

Kolejną rzeczą, jaką sprawdziłem była ilość kartek po narodowości. Chciałem zobaczyć jaka nacja zebrała najwięcej kar:

 

df_2 = df[['Name','Nationality','Yellow_Cards','Red_Cards']].groupby('Nationality').agg({'Yellow_Cards':'sum', 'Red_Cards':'sum','Name':'count'}).sort_values(by=['Yellow_Cards', 'Red_Cards'], ascending=False).head(15)
df_2.rename(columns={'Name':'#_Players'}, inplace=True)

countries = df_2.index
red_cards = df_2['Red_Cards']
yellow_cards = df_2['Yellow_Cards']

fig, ax = plt.subplots(figsize =(16, 9))
ax.barh(countries, yellow_cards, color='gold')
ax.barh(countries, red_cards, left=yellow_cards, color='orangered')
 
# Remove axes splines
for s in ['top', 'bottom', 'left', 'right']:
    ax.spines[s].set_visible(False)

ax.grid(b = True, color ='grey',
        linestyle ='-.', linewidth = 0.5,
        alpha = 0.2)
 
# Show top values
ax.invert_yaxis()
 
x_red = red_cards.tolist()
y_yellow = yellow_cards.tolist()

 

for index, data in enumerate(x_red):
    plt.text(x=data + y_yellow[index], y=index , s=f"{data}" , fontdict=dict(fontsize=14), verticalalignment='center')

 

for index, data in enumerate(y_yellow):
    plt.text(x=data /2 - 5, y=index, s=f"{data}" , fontdict=dict(fontsize=14), verticalalignment='center')
    

 

ax.set_title('Total number of cards (yellow + red) within nationality',
             loc ='left', size=15, fontweight ='bold' )
 
fig.text(0.9, 0, 'mariuszborycki.com', fontsize = 12,
         color ='grey', ha ='right', va ='bottom',
         alpha = 0.7)

plt.yticks(fontsize=12)


plt.show()

 

Mariusz Borycki - ilość kartek po narodowości w Premier League 2020-21

 

Jak widać, większość kartek pochodzi od graczy angielskich, co nikogo nie powinno dziwić, wszak jest to liga angielska. W związku z tym podzieliłem sumę otrzymanych kartek przez ilość graczy dla każdej z narodowości. Wtedy będzie można zobaczyć ile średnio kartek otrzymuje 1 piłkarz z każdego kraju, co wydaje się być bardziej miarodajne:

 

cards_per_nation = df[['Name', 'Nationality', 'Yellow_Cards', 'Red_Cards']].groupby('Nationality').agg({'Yellow_Cards':'sum', 'Red_Cards':'sum', 'Name':'count'})
cards_per_nation['Total_Cards'] = cards_per_nation.Yellow_Cards + cards_per_nation.Red_Cards
cards_per_nation.rename(columns={'Name':'#_Players'}, inplace=True)
cards_per_nation['Cards_per_Player'] = cards_per_nation['Total_Cards'] / cards_per_nation['#_Players']
cards_per_nation = cards_per_nation.sort_values(by=['Cards_per_Player', '#_Players'], ascending=False).reset_index().head(25)

countries = cards_per_nation['Nationality']
cards = cards_per_nation['Cards_per_Player']
 
fig, ax = plt.subplots(figsize =(16, 12))
ax.barh(countries, cards, color='mediumaquamarine')

 

for s in ['top', 'bottom', 'left', 'right']:
    ax.spines[s].set_visible(False)

ax.grid(b = True, color ='grey',
        linestyle ='-', linewidth = 0.2,
        alpha = 0.2)
 
ax.invert_yaxis()

 
for i in ax.patches:
    plt.text(i.get_width()+0.2, i.get_y()+0.5,
             str(round((i.get_width()), 2)),
             fontsize=12,
             color='black') # fontweight ='bold',

ax.set_title('Number of cards (yellow + red) per 1 player within nationality',
             loc='left', size=15, fontweight='bold')
 
fig.text(0.9, 0, 'mariuszborycki.com', fontsize=14,
         color='grey', ha='right', va='bottom',
         alpha=0.7)

plt.yticks(fontsize=12)


plt.show()

 

Mariusz Borycki - ilość kartek na 1 gracza w Premier League

 

Teraz można zauważyć, że ilość otrzymanych kartek na 1 gracza danej narodowości plasuje angielskich piłkarzy na 25 miejscu. Na pierwszym miejscu za to mamy piłkarzy z Mali i Macedonii Północnej. W przypadku Mali w EPL mamy dwóch graczy Moussa Djenepo z Southampton i Yves Bissouma z Brighton, którzy zebrali 14 kartek, tyle samo co jeden piłkarz z Macedonii Północnej - Ezgjan Alioski.

 

Będąc jeszcze w obszarze otrzymanych kartek, chciałem sprawdzić jak wygląda podział kar w zależności od zajmowanej pozycji na boisku:

 

cards_per_position = df[['Name','Position', 'Yellow_Cards', 'Red_Cards']].groupby('Position').agg({'Yellow_Cards':'sum', 'Red_Cards':'sum', 'Name':'count'}).reset_index()
cards_per_position['Total_Cards'] = cards_per_position.Yellow_Cards + cards_per_position.Red_Cards
cards_per_position.rename(columns={'Name':'#_Players'}, inplace=True)
cards_per_position['Cards_per_Position'] = cards_per_position['Total_Cards'] / cards_per_position['#_Players']
cards_per_position = cards_per_position.reset_index(drop=True).sort_values(by=['Cards_per_Position', '#_Players'],ascending=False)

positions = cards_per_position['Position']
cards = cards_per_position['Cards_per_Position']

fig, ax = plt.subplots(figsize =(16, 9))
ax.barh(positions, cards, color='paleturquoise')

 

for s in ['top', 'bottom', 'left', 'right']:
    ax.spines[s].set_visible(False)


# Add annotation to bars
for i in ax.patches:
    plt.text(i.get_width(), i.get_y()+0.4,
             str(round((i.get_width()), 2)),
             fontsize = 12,
             color ='black') # fontweight ='bold'

 

ax.set_title('Number of cards (yellow + red) per 1 player within position',
             loc ='left', size=15, fontweight ='bold' )
 
fig.text(0.9, -0.02, 'mariuszborycki.com', fontsize = 14,
         color ='grey', ha ='right', va ='bottom',
         alpha = 0.7)

plt.yticks(fontsize=12)
plt.xticks(fontsize=12)


plt.show()

 

Mariusz Borycki - ilość kartek po pozycji na boisku

 

Co może wydawać się interesujące, to fakt, że pomocnicy otrzymywali więcej kartek (2,82 kartki na mecz) od obrońców (2,59 kartki na mecz).

 

 


BRAMKI I ASYSTY

Kolejnym obszarem do "zbadania" jest ilość zdobytych bramek i asyst dla wszystkich klubów w EPL:

 

df_goals = df.copy()
df_goals['xGoals'] = round(df_goals.xG * df_goals.Matches,0).astype(int)

df_goals['xG_diff'] =  (df_goals.Goals - df_goals.xGoals).astype(int)


df_goals = df_goals[['Name', 'Club', 'Nationality', 'Position', 'Goals', 'xGoals', 'xG_diff', 'Assists']]\
.groupby('Club').sum()
df_goals['Canadian_Points'] = df_goals.Goals + df_goals.Assists
df_goals = df_goals.sort_values(by='Canadian_Points', ascending=False) 
df_goals

goals = df_goals['Goals']
assists = df_goals['Assists']
clubs = df_goals['Club']
 
fig, ax = plt.subplots(figsize =(16, 9))
ax.bar(clubs, goals, label="Goals", color='darkturquoise')
ax.bar(clubs, assists, bottom=goals, label="Assists", color='paleturquoise')

 

for s in ['top', 'bottom', 'left', 'right']:
    ax.spines[s].set_visible(False)

 

x_goals = goals.tolist()
x_assists = assists.tolist()

 

for ia, da in enumerate(x_assists):
    plt.text(x=ia, y=da / 2 + x_goals[ia] + 1, s=f"{da}", fontdict=dict(fontsize=14), horizontalalignment='center', verticalalignment='center')

 

for ig, dg in enumerate(x_goals):
    plt.text(x=ig, y=dg / 2, s=f"{dg}", fontdict=dict(fontsize=14), horizontalalignment='center', verticalalignment='center')

 

ax.set_title('Amount of Goals and Assists in Premier League - sorted by canadian points',
             loc='left', size=15, fontweight='bold')

fig.text(0.9, -0.1, 'mariuszborycki.com', fontsize = 12,
         color ='black', ha ='right', va ='top',
         alpha = 0.5)

ax.legend(fontsize=12, frameon=False)

plt.tick_params(left = False, right = False, labelleft=False, labelbottom=True, bottom=True)
plt.xticks(clubs,rotation=90,fontsize=12)

 

plt.show()

 

Mariusz Borycki - ilość strzelonych bramek w Premier League 2020-21

 

Najwięcej strzelonych bramek oraz asyst w poprzednim sezonie zdybył Manchester City. Na dalszym stopniu podium uplasowały się kolejno Manchester United oraz Tottenham

 

Warto zobaczyć, który piłkarz miał najwięcej strzelonych bramek oraz kto zaliczył najwięcej asyst w Premier League. 

 

TOP 10 strzelców bramek:

 

df[['Name','Club','Goals']].groupby(['Name','Club']).sum().reset_index().sort_values(by=['Goals'],ascending=False).head(10).plot(x='Name', kind='bar', figsize=(16,8), width=0.8, color='lightseagreen', edgecolor='forestgreen', grid=True)
plt.grid(color='lightgrey', linestyle='-', linewidth=0.3, alpha=0.5)

plt.title('Scored Goals - Top 10 players',loc ='left', size=15, fontweight ='bold')


for index, data in enumerate(df[['Name','Club','Goals']].groupby(['Name','Club']).sum().reset_index().sort_values(by=['Goals'],ascending=False).head(10)['Goals']):
    plt.text(x=index, y=data * 0.9, s=f"{data}", fontdict=dict(fontsize=16), horizontalalignment='center', color='w')


plt.xticks(rotation=45, fontsize=14)
plt.yticks(fontsize=12)
plt.xlabel(None)
plt.legend([], frameon=False)

plt.text(0.8, -0.153, 'mariuszborycki.com', horizontalalignment='center',
         verticalalignment='center', transform=ax.transAxes, color='grey', fontsize=12)

 

plt.show()

 

Mariusz Borycki - TOP10 strzelonych bramek Premier League 2020-21

 

Najwięcej strzelonych bramek miał zawodnik Tottenhamu Harry Kane, który strzelił 23 bramki. Tuż za nim z 22 golami uplasował się Mohamed Salah z Liverpool, a na ostatnim stopniu podium z 18 golami na koncie znalazł się Bruno Fernandes, który gra w zespole Manchester United.

 

TOP 10 piłkarzy z największą ilością asyst:

 

df[['Name','Club','Assists']].groupby(['Name','Club']).sum().reset_index().sort_values(by=['Assists'],ascending=False).head(10).plot(x='Name', kind='bar', figsize=(16,8), width=0.8, color='lightseagreen', edgecolor='forestgreen', grid=True)
plt.grid(color='lightgrey', linestyle='-', linewidth=0.3, alpha=0.5)

plt.title('Assists - Top 10 players',loc ='left', size=15, fontweight ='bold')


for index, data in enumerate(df[['Name','Club','Assists']].groupby(['Name','Club']).sum().reset_index().sort_values(by=['Assists'],ascending=False).head(10)['Assists']):
    plt.text(x=index, y=data * 0.9, s=f"{data}", fontdict=dict(fontsize=16), horizontalalignment='center', color='w')

 

plt.xticks(rotation=45, fontsize=14)
plt.yticks(fontsize=12)
plt.xlabel(None)
plt.legend([], frameon=False)

plt.text(0.8, -0.15, 'mariuszborycki.com', horizontalalignment='center',
         verticalalignment='center', transform=ax.transAxes, color='grey', fontsize=12)

 

plt.show()

 

Mariusz Borycki - TOP10 Asyst w Premier League 2020-21

 

Co ciekawe, na czele zawodników z największą ilością asyst znalazł się Harry Kane z wynikiem 14 asyst w sezonie, czyli ten sam piłkarz, który znajduje się na czele podium wśród najlepszych strzelców w Premier League.  Ex aequo na drugim miejscu znajduje się dwóch piłkarzy z Manchesteru. Mianowicie Bruno Fernandes grający na codzień w drużynie "Czerwonych Diabłów" jak i Kevin De Bruyne z drużyny "The Citizens".

 

TOP 10 w punktacji kanadyjskiej:

 

Kolejnym wskaźnikiem związanym z ilością bramek i asyst są tzw. "punkty kanadyjskie". Jest to rzadko używana statystyka, aczkolwiek pokazuje wpływ jednego piłkarza na wyniki meczów, jako że punkty kanadyjskie są sumą goli i asyst w wybranym czasie (sezon 2020/21 w naszym przypadku). Poniższy wykres pokazuje kto miał najwięcej goli i asyst w poprzednim sezonie EPL:

 

df_canadian = df[['Name', 'Club', 'Position','Goals', 'Assists']].copy()
df_canadian['Cacadian_Points'] = df_canadian.Goals + df_canadian.Assists
df_canadian = df_canadian[['Name','Club','Cacadian_Points','Goals', 'Assists']].groupby(['Name','Club']).sum().reset_index().sort_values(by=['Cacadian_Points'],ascending=False).head(10)

name = df_canadian['Name']
points = df_canadian['Cacadian_Points']
 
fig, ax = plt.subplots(figsize =(16, 9))
ax.bar(name, points, color='lightseagreen')

 

for index, data in enumerate(df_canadian['Cacadian_Points']):
    plt.text(x=index, y=data * 0.9, s=f"{data}", fontdict=dict(fontsize=16), horizontalalignment='center', color='w')

 

for s in ['top', 'bottom', 'left', 'right']:
    ax.spines[s].set_visible(False)


    
ax.grid(b = True, color ='grey',
        linestyle ='-', linewidth = 0.3,
        alpha = 0.2)
 
ax.invert_yaxis()
 
ax.set_title('Canadian Points - Top 10 players',
             loc ='left', size=15, fontweight ='bold')
 
fig.text(0.9, 0.15, 'mariuszborycki.com', fontsize = 12,
         color ='grey', ha ='right', va ='bottom',
         alpha = 0.7)

plt.xticks(name,rotation=45,fontsize=14)
plt.yticks(fontsize=12)

 

plt.show()

 

Mariusz Borycki - TOP10 Kanadyjska punktacja w Premier League 2020-21

 

Jeśli chodzi o punktację kanadyjską, to rzecz jasna na czele klasyfikacji znajduje się Harry Kane. Stawkę TOP 10 zamyka Kevin De Bruyne

 

Stosunek strzelonych bramek do zajmowanej pozycji na boisku: 

Będąc ciekawym jak ma się pozycja na boisku do ilości strzelonych bramek, sprawdziłem czy jest tak, że najwięcej bramek strzelają nominalni napastnicy:

 

# variables
my_labels = df[['Position','Goals']].groupby(['Position']).sum().sort_values(by=['Goals'],ascending=False)\
        .head(10).index.tolist()
my_colors = ['turquoise','lightseagreen','paleturquoise','darkturquoise']
myexplode = [0.2, 0, 0, 0]

 

# plot
df[['Position','Goals']].groupby(['Position']).sum().sort_values(by=['Goals'],ascending=False).head(10)\
        .plot(x='Name',kind='pie', figsize=(16,8), subplots=True, labels=my_labels,startangle=15, 
        shadow=True, colors=my_colors, explode=myexplode, autopct='%1.2f%%', fontsize=16)

plt.title('Goals by position', loc ='left', size=16, fontweight ='bold')
plt.ylabel(None)
plt.axis('equal')

plt.legend([],frameon=False)

plt.text(0.7, -0.1, 'mariuszborycki.com', horizontalalignment='center',
         verticalalignment='center', transform=ax.transAxes, color='grey', fontsize=12)

 

plt.show()

 

Mariusz Borycki - Gole wg pozycji w Premier League 2020-21

 

Także bez większych niespodzianek, prawie 3 bramki na 5 były strzelane przez napastników.

 

Stosunek zdobytych asyst do zajmowanej pozycji na boisku: 

Poniżej analogicznie do powyższego wykresu sprawdziłem, na jakiej pozycji na boisku występuje największe prawdopodobieństwo do zdobycia asysty: 

 

df_assists = df[['Position','Assists']].groupby(['Position']).sum().sort_values(by=['Assists'], ascending=False)
my_colors = ['turquoise','lightseagreen','paleturquoise','darkturquoise']
myexplode = [0.2, 0, 0, 0]

fig, ax = plt.subplots(figsize=(16, 9))

assists = df_assists.Assists.tolist()
possition = df_assists.index.tolist()

 

def func(xx, yy):
    absolute = int(round(xx/100.*np.sum(yy)))
    return "{:.1f}%\n({:d} Assists)".format(xx, absolute)

 

ax.pie(assists, autopct=lambda x: func(x, assists), 
       textprops={'color':"black",'size':16}, # 'fontweight':'bold' 
       labels=possition, startangle=15, shadow=True, colors=my_colors, explode=myexplode)


ax.set_title("Assists by position", loc ='left', size=16, fontweight ='bold')

plt.text(0.9, -0.01, 'mariuszborycki.com', horizontalalignment='center',
         verticalalignment='center', transform=ax.transAxes, color='grey', fontsize=12)

 

plt.show()

 

Mariusz Borycki - asysty wg pozycji na boisku w Premier League 2020-21

 

Co ciekawe, tutaj sytuacja jest dużo bardziej wyrównana. Chociaż nadal na czele stawki znajdują się napastnicy.

 

Oczekiwane bramki (xG):

Dosyć istotną statystyką, a nie tak powszechnie znaną jest tzw. współczynnik "xG" - "Expected Goals", czyli "oczekiwanych goli", który wskazuje ile każdy piłkarz miał klarownych, by nie powiedzieć stuprocentowych sytuacji do strzelenia bramki na mecz.

Na podstawie tego wskaźnika zobaczyłem, który klub jest na czele niewykorzystanych sytuacji bramkowych:

 

df_goals = df_goals.sort_values(by='xG_diff', ascending=False) 

goals = round(df_goals['xG_diff'], 1)
clubs = df_goals.index
 
fig, ax = plt.subplots(figsize =(16, 9))
ax.bar(clubs, goals, label="Goals", color='darkturquoise')

 

for s in ['top', 'bottom', 'left', 'right']:
    ax.spines[s].set_visible(False)

 

x_goals = goals.tolist()

 

for ig, dg in enumerate(x_goals):
    plt.text(x=ig, y=dg / 2, s=f"{dg}", fontdict=dict(fontsize=12), horizontalalignment='center', verticalalignment='center')

 

ax.set_title('Amount of not scored goals in Premier League (scored goals - expected goals)',
             loc ='left', size=15, fontweight ='bold')

fig.text(0.9, -0.1, 'mariuszborycki.com', fontsize = 12,
         color ='black', ha ='right', va ='top',
         alpha = 0.5)

ax.legend([], frameon=False)

plt.tick_params(left = False, right = False, labelleft = False, labelbottom = True, bottom = True)
plt.xticks(clubs,rotation=90,fontsize=12)

 

plt.show()

 

Mariusz Borycki - liczba niewykorzystanych sytuacji bramkowych w Premier League 2020-21

 

Jak widać na powyższym wykresie mistrzem wykorzystywania swoich sytuacji na strzelenie gola jest Crystal Palace. Ciekawie w tym zestawieniu wygląda Chelsea Londyn, która zajęła w tabeli 4 miejsce na koniec sezonu, mimo iż nie wykorzystali około 35 okazji na strzelenie gola.

 

 

Poniżej znajduje się tabelka z wartościami xG dla wszystkich klubów Premier League:

 

Mariusz Borycki - expected goals by club

 

Zawodnicy Chelsea Londyn strzelili 56 goli, a ich wskaźnik xG ocenił, że powinni strzelić około 91 bramek.

 

Oczekiwane Bramki - niewykorzystane okazje:

Sprawdziłem również TOP 10 piłkarzy z pozytywnym stosunkiem bramek do czynnika xG oraz TOP 10 piłkarzy z największą ilością niewykorzystanych okazji strzeleckich.

Najpierw zweryfikowałem listę dziesięciu piłkarzy, którzy mają nawięcej zmarnowanych akcji według wskaźnika xG:

 

df_goals = df.copy()
df_goals['xGoals'] = round(df_goals.xG * df_goals.Matches,0).astype(int)

df_goals['xG_diff'] =  (df_goals.Goals - df_goals.xGoals).astype(int)


df_goals = df_goals[['Name', 'Club', 'Nationality', 'Position', 'Goals', 'xGoals', 'xG_diff', 'Assists']]\
.groupby(['Name']).sum()
df_goals['Canadian_Points'] = df_goals.Goals + df_goals.Assists
df_goals = df_goals.sort_values(by='xG_diff', ascending=True)

goals = df_goals.sort_values(by='xG_diff',ascending=True).head(10)['xG_diff']
names = df_goals.sort_values(by='xG_diff',ascending=True).head(10).index
 
fig, ax = plt.subplots(figsize =(16, 9))
ax.bar(names, goals, label="Goals", color='turquoise')

 

for s in ['top', 'bottom', 'left', 'right']:
    ax.spines[s].set_visible(False)

 

x_goals = goals.tolist()

 

for ig, dg in enumerate(x_goals):
    plt.text(x=ig, y=dg / 2, s=f"{dg}", fontdict=dict(fontsize=12), horizontalalignment='center', verticalalignment='center')

 

ax.set_title('Amount of not scored goals in Premier League (scored goals - expected goals)',
             loc ='left', size=15, fontweight ='bold')

fig.text(0.9, -0.1, 'mariuszborycki.com', fontsize=12,
         color='black', ha='right', va='top',
         alpha = 0.5)

ax.legend([], frameon=False)

plt.tick_params(left=False, right=False, labelleft=False, labelbottom=True, bottom=True)
plt.xticks(names, rotation=90, fontsize=12)

 

plt.show()

 

Mariusz Borycki - LOW 10 for expected goals Premier League 2020-21

 

Fabio Silva nie wykorzystał aż 9 klarownych sytuacji do strzelenia gola. Na drugim miejscu z ośmioma niewykorzystanymi sytuacjami znajduje się aż trzech piłkarzy. Mianowicie są to Aleksandar Mitrovic z FC Fulham, Matej Vydra grający w FC Burnley oraz Timo Werner z Chelsea FC.

 

Oczekiwane Bramki - wykorzystane okazje:

Następnie na tej samej zasadzie zobaczyłem kto jest na liście dziesięciu najlepszych piłkarzy pod kątem wykorzystanych okazji w stosunku do wskaźnika  xG, czyli takich, którzy potrafili strzelić gola mimo niesprzyjających warunków:

 

goals = df_goals.sort_values(by='xG_diff',ascending=False).head(10)['xG_diff']
names = df_goals.sort_values(by='xG_diff',ascending=False).head(10).index

fig, ax = plt.subplots(figsize =(16, 9))
ax.bar(names, goals, label="Goals", color='turquoise')

 

for s in ['top', 'bottom', 'left', 'right']:
    ax.spines[s].set_visible(False)

 

x_goals = goals.tolist()

 

for ig, dg in enumerate(x_goals):
    plt.text(x=ig, y=dg / 2, s=f"{dg}", fontdict=dict(fontsize=12), horizontalalignment='center', verticalalignment='center')

 

ax.set_title('Expected Goals - TOP10 (scored goals - expected goals)',
             loc ='left', size=15, fontweight ='bold')

fig.text(0.9, -0.1, 'mariuszborycki.com', fontsize = 12,
         color ='black', ha ='right', va ='top',
         alpha = 0.5)

ax.legend([], frameon=False)

plt.tick_params(left = False, right = False, labelleft = False, labelbottom = True, bottom = True)
plt.xticks(names,rotation=90,fontsize=12)

 

plt.show()

 

Mariusz Borycki - TOP 10 expected goals Premier League 2020-21

 

Mistrzem strzelania goli "z niczego" był zawodnik Tottenham Hotspur Heung-min Son, który strzelił aż 6 bramek z trudnej pozycji.

 

 


PRÓBY ODDANYCH PODAŃ

 

Kolejnym obszarem zweryfikowanym przeze mnie była lista TOP 10 piłkarzy z największą ilością podań w zeszłym sezonie Ligi Angielskiej:

 

df[['Name','Club','Passes_Attempted']].groupby(['Name','Club']).sum().reset_index().sort_values(by=['Passes_Attempted'],ascending=False).head(10).plot(x='Name', kind='bar', figsize=(16,8), width=0.8, color='turquoise', edgecolor='forestgreen', grid=True)

passes = df[['Name','Club','Passes_Attempted']].groupby(['Name','Club']).sum().reset_index().sort_values(by=['Passes_Attempted'], ascending=False).head(10)['Passes_Attempted'].to_list()


for index, data in enumerate(passes):
    plt.text(x=index, y=data * 0.9, s=f"{data}", fontdict=dict(fontsize=14), horizontalalignment='center')

 

plt.grid(color='lightgrey', linestyle='-', linewidth=0.7, alpha=0.2)
plt.xlabel(None)
plt.xticks(rotation=45, size=14)
plt.title('Passes Attempted - Top 10 players', loc='left', size=15, fontweight='bold')

plt.legend([], frameon=False)

plt.text(0.8, -0.15, 'mariuszborycki.com', horizontalalignment='center',
         verticalalignment='center', transform=ax.transAxes, color='grey', fontsize=14)

 

plt.show()

 

Mariusz Borycki - Ilość podań - TOP10 w Premier League 2020-21

 

Powyższy wykres pokazuje, że stawka była całkiem wyrównana. Natomiast nieco większą przewagę nad kolegami uzyskał zawodnik, znajdujący się na czele stawki grający w Liverpool F.C - Andrew Robertson, z wynikiem 3214 podań w sezonie.

 

Przygotowałem również listę piłkarzy z najbardziej dokładnymi podaniami. Co ważne, wziąłem pod uwagę tylko piłkarzy, którzy mają więcej niż 1000 podań w sezonie. Moje założenie wynika z zamiaru nie brania pod uwagę piłkarzy, którzy grali mało:

 

df.loc[df.Passes_Attempted>1000,['Name', 'Club', 'Perc_Passes_Completed']].groupby(['Name', 'Club']).sum().reset_index().sort_values(by=['Perc_Passes_Completed'],ascending=False).head(15).plot(x='Name', kind='bar', figsize=(18,8), color='turquoise', grid=False, width=0.90)

plt.title('Accurate Passes Attempted (%) - Top 15 players', loc='left', size=15, fontweight='bold')

passes_accur = df.loc[df.Passes_Attempted>1000,['Name','Club', 'Perc_Passes_Completed']].groupby(['Name','Club']).sum().reset_index().sort_values(by=['Perc_Passes_Completed'], ascending=False).head(15)['Perc_Passes_Completed'].tolist()


for index, data in enumerate(passes_accur):
    plt.text(x=index, y=data -1, s=f"{data}%", fontdict=dict(fontsize=14), horizontalalignment='center', color='w',fontweight ='bold')

 

plt.xticks(rotation=45, size=14)
plt.yticks(size=14)
plt.xlabel(None)
plt.ylim(86, 96)
plt.tick_params(left = False, right = False, labelleft = False, labelbottom = True, bottom = True)

plt.legend([], frameon=False)

plt.text(0.88,-0.15, 'mariuszborycki.com', horizontalalignment='center',
         verticalalignment='center', transform=ax.transAxes, color='grey', fontsize=14)

 

plt.show()

 

Mariusz Borycki - dokładność podań - TOP15 w Premier League 2020-21

 

 


WIEK PIŁKARZY

Kolejnym obszarem jaki wziąłem pod lupę był wiek piłkarzy. Na początek przygotowałem listę 15 najstarszych piłkarzy w lidze:

 

df_age_high = df[['Name', 'Club', 'Position', 'Age']].sort_values(by=['Age'], ascending=False).head(15)

name = df_age_high['Name']
age = df_age_high['Age']

fig, ax = plt.subplots(figsize=(16,10))
ax.bar(name,age,color='lightseagreen')

 

for s in ['top', 'bottom', 'left', 'right']:
    ax.spines[s].set_visible(False)

    
for index, data in enumerate(age):
    plt.text(x=index, y=data * 0.9, s=f"{data}", fontdict=dict(fontsize=14), horizontalalignment='center', color='w', fontsize=16)

 

ax.set_title('Top 15 the oldest players',
             loc ='left', size=15, fontweight ='bold' )
 
fig.text(0.9, -0.05, 'mariuszborycki.com', fontsize = 12,
         color ='grey', ha ='right', va ='bottom',
         alpha = 0.7)

plt.tick_params(left = False, right = False, labelleft = False, labelbottom = True, bottom = True)

ax.invert_yaxis()
plt.yticks(fontsize=12)
plt.xticks(fontsize=14, rotation=45)


plt.show()

 

Mariusz Borycki - najstarsi piłkarze w Premier League 2020-21

 

W Premier League w sezonie 2020/21 mieliśmy 9 piłkarzy, którzy skończyli 35 lat. Najstarszy z nich to argentyński bramkarz Chelsea F.C Willy Caballero, który skończył 38 lat.

 

Lista 15 najmłodszych piłkarzy ligi:

 

df_age_low = df[['Name', 'Club', 'Position', 'Age']].sort_values(by=['Age'], ascending=True).head(15)

name = df_age_low['Name']
age = df_age_low['Age']

fig, ax = plt.subplots(figsize=(16,10))
ax.bar(name,age,color='lightseagreen')

 

for s in ['top', 'bottom', 'left', 'right']:
    ax.spines[s].set_visible(False)


for index, data in enumerate(age):
    plt.text(x=index, y=data * 0.9, s=f"{data}", fontdict=dict(fontsize=14), horizontalalignment='center', color='w', fontsize=16)

 

ax.set_title('Top 15 the youngest players',
             loc ='left', size=15, fontweight ='bold' )
 
fig.text(0.9, -0.05, 'mariuszborycki.com', fontsize = 12,
         color ='grey', ha ='right', va ='bottom',
         alpha = 0.7)

plt.tick_params(left = False, right = False, labelleft = False, labelbottom = True, bottom = True)

ax.invert_yaxis()
plt.yticks(fontsize=12)
plt.xticks(fontsize=14, rotation=45)


plt.show()

 

Mariusz Borycki - najmłodsi piłkarze w Premier League 2020-21

 

W poprzenim sezonie w klubach Ligi Angielskiej występowało 12 zawodników, którzy nie mieli jeszcze ukończonych 18 lat.

 

Średni wiek po pozycji:

 

df_position = df[['Position','Age']].groupby(['Position']).mean().round(1).sort_values(by='Age')

fig, ax = plt.subplots(figsize=(16, 10))
age = df_position['Age']
position = df_position.index
ax.bar(position,age,color='lightseagreen')

 

for s in ['top', 'bottom', 'left', 'right']:
    ax.spines[s].set_visible(False)


for index, data in enumerate(age):
    plt.text(x=index, y=data * 0.9, s=f"{data}", fontdict=dict(fontsize=14), horizontalalignment='center', color='w', fontsize=16)

 

ax.legend([], frameon=False)
ax.set_title("Average age by positions in Premier League", size=16, loc='left', fontweight='bold')

plt.tick_params(left = False, right = False, labelleft = False, labelbottom = True, bottom = True)
 
fig.text(0.9, -0.05, 'mariuszborycki.com', fontsize = 12,
         color ='grey', ha ='right', va ='bottom',
         alpha = 0.7)

plt.yticks(fontsize=12)
plt.xticks(fontsize=14, rotation=45)

 

plt.show()

 

Mariusz Borycki - średni wiek wg pozycji na boisku w Premier League 2020-21

 

Tutaj bez większych niespodzianek. Wiek piłkarzy jest w miarę wyrównany nie licząc pozycji bramkarza (28,2 lata), na której średnia wieku jest o 3 lata wyższa niż w przypadku pomocników (25,1 lat).

 

Wiek piłkarzy w każdej drużynie Premier League:

 

df_club_ages = df[['Club','Age']].groupby('Club').mean().round(1).sort_values(by=['Age'], ascending=True)

fig, ax = plt.subplots(figsize=(16, 10))
age = df_club_ages['Age']
club = df_club_ages.index
ax.bar(club,age,color='lightseagreen')

 

for s in ['top', 'bottom', 'left', 'right']:
    ax.spines[s].set_visible(False)


for index, data in enumerate(age):
    plt.text(x=index, y=data * 0.9, s=f"{data}", horizontalalignment='center', color='w', fontsize=14)

 

ax.legend([], frameon=False)
ax.set_title("Average age in all clubs in Premier League",
             loc ='left', size=15, fontweight ='bold')

plt.tick_params(left = False, right = False, labelleft = False, labelbottom = True, bottom = True)
 
fig.text(0.9, -0.09, 'mariuszborycki.com', fontsize = 12,
         color ='grey', ha ='right', va ='bottom',
         alpha = 0.7)

plt.yticks(fontsize=12)
plt.xticks(fontsize=14, rotation=90)

 

plt.show()

 

Mariusz Borycki - średni wiek w klubach Premier League 2020-21

 

Najstarsza drużyna Crystal Palace jest średnio o 4 lata starsza od najmłodszej drużyny w lidze, jaką jest Manchester United.

 

Zakres wieku po klubach ligi angielskiej:

 

plt.figure(figsize=(20,10))
sns.boxplot(x='Club', y='Age', data=df.sort_values(by='Age'))
plt.yticks(fontsize=12)
plt.xticks(fontsize=14, rotation=90)
plt.xlabel(None)
plt.ylabel('Age', size=14)

plt.title("Age range in all clubs in Premier League",
             loc='left', size=18, fontweight='bold')

plt.text(1.05, -0.15, 'mariuszborycki.com', horizontalalignment='center',
         verticalalignment='center', transform=ax.transAxes, color='grey', fontsize=14)

plt.show()

 

Mariusz Borycki - zakres wieku w klubach Premier League 2020-21

 

Na powyższym tzw. wykresie pudełkowym można zobaczyć szczegółowy przedział wiekowy od najmłodszych do najstarszych zawodników, w każdym klubie Premier League w badanym sezonie.

Na przykładzie Tottenhamu widać, że najmłodszy zawodnik ma zaledwie 16 lat. Następny w kolejności jest zawodnik aż o 5 lat starszy i ma 21 lat.

Nastarszy z kolei zawodnik "Spurs" ma 33 lata. Natomiast mediana wieku w tym klubie waha się między 25tym, a 26tym rokiem życia. 

 

Narodowość w Lidze Angielskiej:

 

df.loc[df.Nationality!='ENG',['Club', 'Nationality']].drop_duplicates().groupby('Club').count().reset_index().sort_values(by= 'Nationality').plot(x='Club', kind='bar', figsize=(18,10), color='darkturquoise', grid=False, width=0.85)


plt.title('Amount of nations in the Premier League clubs (excluding ENG)', loc='left', size=18, fontweight ='bold')

nationalities = df.loc[df.Nationality!='ENG', ['Club', 'Nationality']].drop_duplicates().groupby('Club').count().sort_values(by='Nationality')['Nationality'].tolist()


for index, data in enumerate(nationalities):
    plt.text(x=index, y=data -1, s=f"{data}", fontdict=dict(fontsize=18), horizontalalignment='center', color='w')

 

plt.xticks(rotation=90, size=14)
plt.yticks(size=14)
plt.xlabel(None)
plt.tick_params(left = False, right = False, labelleft = False, labelbottom = True, bottom = True)

plt.legend([], frameon=False)


plt.text(0.88, -0.05, 'mariuszborycki.com', horizontalalignment='center',
         verticalalignment='center', transform=ax.transAxes, color='grey', fontsize=14)

 

plt.show()

 

Mariusz Borycki - liczba narodowości w klubach Premier League 2020-21

 

Ostatnim przygotowanym przeze mnie wykresem jest wartość liczbowa wskazująca ile różnych narodowości znajduje się w każdym klubie Premier League, wyłączając pochodzenie angielskie. Co może wydawać się dla kogoś zaskakujące, to że w jednym klubie takim jak Liverpool czy Fulham znajduje się aż 16 zawodników pochodzących z różnych krajów.

W przypadku drużyny "The Reds" mówimy o klubie, który zajął 3 miejsce w lidze i widocznie ta multikulturowość mogła mieć pozytywny wpływ na osiągnięte wyniki. Tego z kolei nie możemy powiedzieć o drużynie z Londynu - Fulham F.C., która zajęła 18 miejsce z dużą stratą do 17go Burnley (11 punktów) co przełożyło się na spadek z ligi.

 

 


NA KONIEC

Jeśli masz jakieś pytania lub wolne wnioski dotyczące mojej analizy to zapraszam do pozostawienia komentarza.

Natomiast jeżeli masz pomysły na kolejne projekty lub w razie jakichkolwiek innych pytań zapraszam do kontaktu.

 

Wszystkie skrypty wraz z ich opisem znajdują się w moim repozytorium na platformie GitHub oraz w Kaggle, gdzie serdecznie zapraszam.

Comments:

0 comments

There is no comment yet.

Add new comment: