Skip to article content

Étude des relations entre l'entraîneur sportif et la performance du club

Back to Article
Exploratory Data Analysis
Download Notebook

Exploratory Data Analysis

from pathlib import Path

import matplotlib.pyplot as plt
import matplotlib.ticker as mticker
import polars as pl
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 = pl.read_csv(
    Path("./../data/match_results.csv"),
).cast(
    {
        "DaysInPost": pl.Int64,
        "Goals": pl.Int64,
        "Date": pl.Date,
    }
)

match_results.head()
Loading...
head_coach = pl.read_csv(Path("./../data/head_coach.csv")).cast(
    {"Appointed": pl.Date, "EndDate": pl.Date}
)
head_coach.head()
Loading...
first_season = match_results.get_column("Date").dt.year().min() + 1
last_season = match_results.get_column("Date").dt.year().max()
leagues = ", ".join(match_results.get_column("League").unique())
n_match = round(len(match_results) / 2)
n_team = match_results.get_column("Team").n_unique()
n_team_no_coach = (
    match_results.group_by("Team")
    .agg(pl.col("HeadCoach").is_null().all().alias("all_null"))
    .filter(pl.col("all_null"))
    .height
)
perc_match_no_coach = match_results.get_column("HeadCoach").is_null().sum() / len(
    match_results
)
n_coach = head_coach.get_column("HeadCoach").n_unique()
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 Unexecuted inline expression for: first_season - Unexecuted inline expression for: last_season 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 Unexecuted inline expression for: f'{perc_match_no_coach:.2%}' 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.group_by(["League", "Country"])
    .agg(
        [
            pl.col("Team").n_unique().alias("Number of Teams"),
            pl.col("Date").len().alias("Number of Matches"),
            (
                (pl.col("HeadCoach").is_null().sum() / pl.col("HeadCoach").len() * 100)
                .round(2)
                .cast(pl.String)
                + "%"
            ).alias("Percentage of Matches without Head Coach"),
        ]
    )
    .sort("Number of Matches", descending=True)
)

match_summary
Loading...
# Plot distribution of match
plt.figure()
sns.histplot(
    match_results.get_column("Date").dt.month(),
    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))
plt.gca().set_xticks(range(1, 13))
plt.gca().set_xticklabels(
    ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
)
plt.show()
<Figure size 1920x1440 with 1 Axes>

Effet du jeu à domicile ou à l’extérieur sur la performance des équipes

mean_home_goals = match_results.filter(pl.col("isHome")).get_column("Goals").mean()
mean_away_goals = match_results.filter(~pl.col("isHome")).get_column("Goals").mean()
diff_goal_perc = (mean_home_goals - mean_away_goals) / mean_away_goals

L’équipe qui joue à domicile marque en moyenne 1.50 but contre 1.18 but pour l’équipe jouant à l’extérieur (Unexecuted inline expression for: f'{diff_goal_perc:.2%}' moins de buts).

match_result_home_away = (
    match_results.group_by(["isHome", "Result"])
    .len()
    .with_columns(proportion=pl.col("len") / pl.col("len").sum().over("isHome"))
    .select(
        pl.col("isHome")
        .replace_strict({True: "Home", False: "Away"})
        .alias("Team venue"),
        pl.col("Result").str.to_titlecase(),
        pl.format("{} %", (pl.col("proportion") * 100).round(1)).alias(
            "Proportion (%)"
        ),
    )
    .sort("Team venue", "Result", descending=True)
)

match_result_home_away
Loading...
home_stats = match_result_home_away.filter(pl.col("Team venue") == "Home").get_column(
    "Proportion (%)"
)
away_stats = match_result_home_away.filter(pl.col("Team venue") == "Away").get_column(
    "Proportion (%)"
)

perc_home_win = home_stats.item(0)
perc_home_loss = home_stats.item(1)
perc_away_win = away_stats.item(0)
perc_away_loss = away_stats.item(1)
perc_draw = home_stats.item(2)

Les équipes jouant à domicile remportent Unexecuted inline expression for: f'{perc_home_win}' de leurs matchs contre Unexecuted inline expression for: f'{perc_away_win}' pour les équipes jouant à l’extérieur. Les équipes perdent Unexecuted inline expression for: f'{perc_home_loss}' de leurs matchs contre Unexecuted inline expression for: f'{perc_away_loss}' pour les équipes jouant à l’extérieur. Les matchs nuls représentent Unexecuted inline expression for: f'{perc_draw}' des matchs.

Étude des relations entre l'entraîneur sportif et la performance du club
Preprocessing
Étude des relations entre l'entraîneur sportif et la performance du club
Head Coaches