Étude des relations entre l'entraîneur sportif et la performance du club
Exploratory Data Analysis
import pandas as pd
from math import floor
import matplotlib.pyplot as plt
import matplotlib.ticker as mticker
import seaborn as sns
sns.set_theme(context = 'paper', style = 'ticks', palette = 'deep', color_codes = True)
plt.rcParams['figure.autolayout'] = True
plt.rcParams['figure.dpi'] = 300
EDA of match_results¶
match_results = pd.read_csv('data/match_results.csv', parse_dates=['Date'], dtype = {'HeadCoach' : 'str'})
match_results.head()
head_coach = pd.read_csv('data/head_coach.csv', dtype = {'HeadCoach' : 'str'}, parse_dates=['Appointed', 'EndDate'])
min_season = match_results['Date'].dt.year.min() + 1
max_season = match_results['Date'].dt.year.max()
leagues = ", ".join(match_results['League'].unique())
n_match = floor(len(match_results) / 2)
n_team = match_results['Team'].nunique()
n_team_no_coach = match_results.groupby(['Team'])['HeadCoach'].apply(lambda x: x.isnull().all()).sum()
perc_match_no_coach = (match_results['HeadCoach'].isnull().sum() / len(match_results)) * 100
n_coach = head_coach['HeadCoach'].nunique()
n_appointments = len(head_coach)
Nous avons collecté les résultats des matchs et les mandats des entraîneurs sportif chef de la première division masculine de football pour les saisons 2015 - 2023 et pour les ligues suivantes : 'Premier League, La Liga, Ligue 1, Bundesliga, Serie A'.
Cela correspond à un total de 14361 matchs joués par 161 équipes. Parmi ces 161 équipes, 95 équipes n’ont pas d’information sur les mandats des entraîneurs chefs pour tout ou partie des saisons 2015 à 2023. En proportion de match c’est '46' % des matchs qui ne comportent pas d’information sur l’entraîneur chef.
Les données des mandats des entraîneurs sportifs contiennent 381 mandat d’entraîneurs chefs parmi 249 entraîneurs uniques.
match_summary = match_results.groupby(['League', 'Country']).agg(
{
'Team' : 'nunique',
'Date' : 'size',
'HeadCoach': lambda x: str(round((x.isnull().sum() / len(x)) * 100, 2)) + '%'
}
)
match_summary.columns = ['Number of Teams', 'Number of Matches', 'Percentage of Matches without Head Coach']
match_summary.sort_values(by = 'Number of Matches', ascending = False)
# Plot distribution of match
plt.figure()
sns.histplot(match_results['Date'].dt.month, bins=12, stat='density', discrete = True, alpha = 1)
plt.title('Monthly Distribution of Matches')
plt.xlabel('Month')
plt.ylabel('Density')
plt.gca().yaxis.set_major_formatter(mticker.PercentFormatter(xmax=1))
months = pd.date_range('2022-01-01', '2022-12-31', freq='ME').strftime('%b').tolist()
plt.xticks(range(1, 13), months);
Effet du jeu à domicile ou à l’extérieur sur la performance des équipes¶
home_goal = match_results[match_results['isHome']]['Goals'].mean()
away_goal = match_results[~match_results['isHome']]['Goals'].mean()
diff_goal_perc = ((home_goal - away_goal) / home_goal) * 100
home_win = match_results[match_results['isHome']]['Result'].value_counts(normalize=True)['win']
away_win = match_results[~match_results['isHome']]['Result'].value_counts(normalize=True)['win']
diff_win_perc = (home_win - away_win) * 100
home_draw = match_results[match_results['isHome']]['Result'].value_counts(normalize=True)['draw']
En moyenne, l’équipe qui joue à domicile marque '1.50' but contre '1.18' but pour l’équipe jouant à l’extérieur ('22'% moins de buts). Ainsi, les équipes jouant remportent '43' % de leurs matchs contre '29' % pour les équipes jouant à l’extérieur. Les matchs nuls représentent '25' % des matchs.
plt.figure()
sns.countplot(data=match_results[match_results['isHome']], x='Result', hue = "Result",
order = ['win', 'draw', 'loss'], stat = 'proportion', palette = ['red', 'green', 'gray'], alpha = 0.75)
plt.title('Match Outcome for Team playing at Home')
plt.xlabel('')
plt.ylabel('Percentage of Matches')
plt.gca().yaxis.set_major_formatter(mticker.PercentFormatter(xmax=1))