📈 Module 12 — Visualisation avec R & Python
Acte IV — R & Python pour l'analyse de données
Niveau : Débutant · Durée estimée : 3h30
🎯 Objectifs du module
À la fin de ce module, tu sauras :
- Choisir le bon type de graphique selon la question posée
- Créer des graphiques en Python avec matplotlib et seaborn
- Créer des graphiques en R avec ggplot2
- Personnaliser titres, couleurs, étiquettes
- Sauvegarder un graphique en image (PNG, PDF)
- Produire un mini-rapport visuel sur les données RH
🌍 Mise en contexte — Bamba & Associés, Abidjan
M. Bamba a reçu le rapport statistique d'Ama. Il est satisfait des chiffres, mais il veut aller plus loin :
"Ama, les tableaux c'est bien, mais moi je dois présenter ça au Conseil d'Administration. J'ai besoin de graphiques clairs. Un graphique vaut mille chiffres."
C'est le rôle de la visualisation de données : transformer des chiffres en images qui racontent une histoire.
1. Quel graphique pour quelle question ?
Le choix du graphique dépend de ce que tu veux montrer :
| Question | Type de graphique | Exemple |
|---|---|---|
| Distribution d'une variable numérique | Histogramme | Distribution des salaires |
| Comparer des groupes (valeurs) | Barres | Salaire moyen par département |
| Comparer des groupes (dispersion) | Boîte à moustaches | Salaires CDI vs CDD |
| Répartition en % | Camembert / Donut | % de CDI, CDD, Stage |
| Relation entre 2 variables numériques | Nuage de points | Ancienneté vs Salaire |
| Évolution dans le temps | Courbe (ligne) | CA mensuel |
| Plusieurs variables en une vue | Pairplot / Heatmap | Corrélations globales |
Les erreurs classiques à éviter
| Erreur | Pourquoi c'est un problème |
|---|---|
| Camembert avec 8 tranches | Illisible — utiliser un barplot à la place |
| Axe Y qui ne commence pas à 0 | Exagère visuellement les différences |
| Couleurs sans signification | Distrait du message principal |
| Titre absent | Le lecteur ne sait pas quoi regarder |
| Trop de graphiques sur une slide | Un graphique = un message |
2. Préparer les données
On reprend le dataset RH Bamba & Associés du module 11 (15 employés).
En Python
pythonimport pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
# Style global seaborn
sns.set_theme(style="whitegrid", palette="Blues_d")
data = {
"nom": ["Kouassi Ama", "Kouamé Jean", "Traoré Seydou", "Diabaté Fatou",
"Bamba Koné", "Ouédraogo Moussa", "Soro Aminata", "Koné Ibrahim",
"Yao Adjoua", "Diallo Mamadou", "Coulibaly Assata", "N'Guessan Éric",
"Touré Mariam", "Keita Souleymane", "Fofana Raïssa"],
"departement": ["RH", "Finance", "Commercial", "RH", "Direction",
"IT", "Commercial", "Finance", "IT", "Commercial",
"RH", "Finance", "IT", "Commercial", "Direction"],
"contrat": ["CDI", "CDI", "CDI", "CDD", "CDI", "CDI", "Stage", "CDI",
"CDI", "CDD", "CDI", "CDI", "Stage", "CDI", "CDI"],
"salaire": [450000, 620000, 380000, 310000, 1800000, 580000, 180000,
540000, 610000, 340000, 420000, 590000, 200000, 360000, 950000],
"anciennete": [5, 8, 3, 1, 12, 6, 0, 7, 9, 2, 4, 7, 0, 3, 10]
}
df = pd.DataFrame(data)En R
rlibrary(ggplot2)
library(dplyr)
df <- data.frame(
nom = c("Kouassi Ama", "Kouamé Jean", "Traoré Seydou", "Diabaté Fatou",
"Bamba Koné", "Ouédraogo Moussa", "Soro Aminata", "Koné Ibrahim",
"Yao Adjoua", "Diallo Mamadou", "Coulibaly Assata", "N'Guessan Éric",
"Touré Mariam", "Keita Souleymane", "Fofana Raïssa"),
departement = c("RH", "Finance", "Commercial", "RH", "Direction",
"IT", "Commercial", "Finance", "IT", "Commercial",
"RH", "Finance", "IT", "Commercial", "Direction"),
contrat = c("CDI", "CDI", "CDI", "CDD", "CDI", "CDI", "Stage", "CDI",
"CDI", "CDD", "CDI", "CDI", "Stage", "CDI", "CDI"),
salaire = c(450000, 620000, 380000, 310000, 1800000, 580000, 180000,
540000, 610000, 340000, 420000, 590000, 200000, 360000, 950000),
anciennete = c(5, 8, 3, 1, 12, 6, 0, 7, 9, 2, 4, 7, 0, 3, 10)
)3. Histogramme — Distribution des salaires
L'histogramme montre comment les valeurs se répartissent : où se concentrent les salaires, y a-t-il des valeurs extrêmes ?
Python — matplotlib
pythonplt.figure(figsize=(9, 5))
plt.hist(df['salaire'], bins=6, color='#2196F3', edgecolor='white')
plt.title('Distribution des salaires — Bamba & Associés', fontsize=14, fontweight='bold')
plt.xlabel('Salaire (FCFA)')
plt.ylabel('Nombre d\'employés')
plt.axvline(df['salaire'].mean(), color='red', linestyle='--', label=f"Moyenne : {df['salaire'].mean():,.0f}")
plt.axvline(df['salaire'].median(), color='orange', linestyle='--', label=f"Médiane : {df['salaire'].median():,.0f}")
plt.legend()
plt.tight_layout()
plt.savefig('histogramme_salaires.png', dpi=150)
plt.show()Python — seaborn (plus joli, même résultat)
pythonplt.figure(figsize=(9, 5))
sns.histplot(df['salaire'], bins=6, kde=True, color='#2196F3')
plt.title('Distribution des salaires — Bamba & Associés')
plt.xlabel('Salaire (FCFA)')
plt.ylabel('Effectif')
plt.show()
# kde=True ajoute une courbe de densité lissée par-dessusR — ggplot2
rggplot(df, aes(x = salaire)) +
geom_histogram(bins = 6, fill = "#2196F3", color = "white") +
geom_vline(aes(xintercept = mean(salaire)), color = "red", linetype = "dashed") +
geom_vline(aes(xintercept = median(salaire)), color = "orange", linetype = "dashed") +
labs(
title = "Distribution des salaires — Bamba & Associés",
subtitle = "Ligne rouge = moyenne | Ligne orange = médiane",
x = "Salaire (FCFA)",
y = "Nombre d'employés"
) +
theme_minimal()📌 Lecture du graphique : la majorité des salaires se concentrent entre 300k et 650k FCFA. Le salaire de 1 800 000 (Bamba Koné) est clairement isolé à droite — c'est l'outlier identifié en M11.
4. Graphique en barres — Salaire moyen par département
Les barres permettent de comparer des catégories entre elles.
Python — seaborn
python# Calculer la moyenne par département
moy_dept = df.groupby('departement')['salaire'].mean().sort_values(ascending=False).reset_index()
plt.figure(figsize=(9, 5))
sns.barplot(data=moy_dept, x='departement', y='salaire', palette='Blues_d')
plt.title('Salaire moyen par département', fontsize=14, fontweight='bold')
plt.xlabel('Département')
plt.ylabel('Salaire moyen (FCFA)')
plt.xticks(rotation=15)
# Ajouter les valeurs sur les barres
for i, v in enumerate(moy_dept['salaire']):
plt.text(i, v + 10000, f"{v:,.0f}", ha='center', fontsize=9)
plt.tight_layout()
plt.show()
# Direction : 1 375 000 | Finance : 583 333 | IT : 463 333
# RH : 393 333 | Commercial : 315 000R — ggplot2
rdf %>%
group_by(departement) %>%
summarise(salaire_moyen = mean(salaire)) %>%
arrange(desc(salaire_moyen)) %>%
ggplot(aes(x = reorder(departement, -salaire_moyen), y = salaire_moyen)) +
geom_col(fill = "#2196F3") +
geom_text(aes(label = scales::comma(round(salaire_moyen))),
vjust = -0.5, size = 3.5) +
labs(
title = "Salaire moyen par département",
x = "Département",
y = "Salaire moyen (FCFA)"
) +
theme_minimal()📌 Lecture : Direction écrase les autres départements à cause du salaire du DG. Si on exclut la Direction, Finance est en tête avec 583 000 FCFA de moyenne.
5. Boîte à moustaches — Dispersion par groupe
La boîte à moustaches (boxplot) montre la médiane, les quartiles et les outliers en même temps. Idéale pour comparer des groupes.
Anatomie d'un boxplot :
┌───────────┐
───────┤ ├─────── ← moustaches (min/max hors outliers)
│ Q2 │ ← ligne centrale = médiane
└───────────┘
Q1 Q3
○ ← point isolé = outlierPython — seaborn
pythonplt.figure(figsize=(9, 5))
sns.boxplot(data=df, x='contrat', y='salaire',
order=['CDI', 'CDD', 'Stage'],
palette=['#1565C0', '#42A5F5', '#90CAF9'])
plt.title('Distribution des salaires par type de contrat', fontsize=14, fontweight='bold')
plt.xlabel('Type de contrat')
plt.ylabel('Salaire (FCFA)')
plt.tight_layout()
plt.show()
# CDI : médiane ≈ 570 000, outlier = 1 800 000
# CDD : médiane ≈ 340 000
# Stage : médiane ≈ 190 000R — ggplot2
rggplot(df, aes(x = contrat, y = salaire, fill = contrat)) +
geom_boxplot(outlier.color = "red", outlier.size = 3) +
scale_fill_manual(values = c(CDI = "#1565C0", CDD = "#42A5F5", Stage = "#90CAF9")) +
labs(
title = "Distribution des salaires par type de contrat",
x = "Type de contrat",
y = "Salaire (FCFA)"
) +
theme_minimal() +
theme(legend.position = "none")📌 Lecture : Les CDI ont la plus grande dispersion — allant de 310 000 à 1 800 000. Les Stage sont concentrés entre 180k et 200k. L'outlier rouge (CDI) est Bamba Koné.
6. Camembert — Répartition des contrats
Le camembert convient aux proportions quand il y a peu de catégories (≤ 5).
Python — matplotlib
pythoncontrats = df['contrat'].value_counts()
# CDI: 10, CDD: 3, Stage: 2
couleurs = ['#1565C0', '#42A5F5', '#90CAF9']
explode = [0.05, 0, 0] # légèrement détacher la première tranche
plt.figure(figsize=(7, 7))
plt.pie(
contrats,
labels=contrats.index,
autopct='%1.0f%%',
colors=couleurs,
explode=explode,
startangle=90
)
plt.title('Répartition des types de contrat\nBamba & Associés', fontsize=13, fontweight='bold')
plt.show()
# CDI : 67% | CDD : 20% | Stage : 13%R — ggplot2 (donut)
rcontrats <- df %>%
count(contrat) %>%
mutate(pct = round(n / sum(n) * 100))
ggplot(contrats, aes(x = 2, y = n, fill = contrat)) +
geom_col() +
coord_polar(theta = "y") +
xlim(0.5, 2.5) +
geom_text(aes(label = paste0(pct, "%")),
position = position_stack(vjust = 0.5), color = "white", size = 5) +
scale_fill_manual(values = c(CDI = "#1565C0", CDD = "#42A5F5", Stage = "#90CAF9")) +
labs(title = "Répartition des contrats — Bamba & Associés", fill = "Contrat") +
theme_void()📌 Lecture : 2 employés sur 3 sont en CDI. Les stagiaires représentent 13% de l'effectif.
7. Nuage de points — Ancienneté vs Salaire
Le scatter plot explore la relation entre deux variables numériques : est-ce que les employés anciens gagnent plus ?
Python — seaborn
pythonplt.figure(figsize=(9, 6))
sns.scatterplot(
data=df,
x='anciennete',
y='salaire',
hue='departement',
size='salaire',
sizes=(60, 400),
palette='tab10'
)
# Ajouter une droite de tendance
sns.regplot(data=df, x='anciennete', y='salaire',
scatter=False, color='gray', line_kws={'linestyle': '--'})
plt.title('Ancienneté vs Salaire par département', fontsize=14, fontweight='bold')
plt.xlabel('Ancienneté (années)')
plt.ylabel('Salaire (FCFA)')
plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left')
plt.tight_layout()
plt.show()
# Tendance : plus on est anciens, plus le salaire tend à augmenter
# Bamba Koné (12 ans, 1 800 000) est très au-dessus de la droiteR — ggplot2
rggplot(df, aes(x = anciennete, y = salaire, color = departement, size = salaire)) +
geom_point(alpha = 0.8) +
geom_smooth(method = "lm", se = FALSE, color = "gray",
linetype = "dashed", linewidth = 0.8, aes(group = 1)) +
scale_size(range = c(3, 10), guide = "none") +
labs(
title = "Ancienneté vs Salaire par département",
x = "Ancienneté (années)",
y = "Salaire (FCFA)",
color = "Département"
) +
theme_minimal()📌 Lecture : la droite de tendance confirme une corrélation positive — l'ancienneté est associée à des salaires plus élevés. Bamba Koné (point rouge en haut à droite) tire la droite vers lui.
8. Sauvegarder et personnaliser
Sauvegarder un graphique
python# Python — toujours AVANT plt.show()
plt.savefig('mon_graphique.png', dpi=150, bbox_inches='tight')
plt.savefig('mon_graphique.pdf') # format vectoriel pour impressionr# R — sauvegarder le dernier graphique ggplot2
ggsave("mon_graphique.png", width = 10, height = 6, dpi = 150)
ggsave("mon_graphique.pdf", width = 10, height = 6)Personnaliser les couleurs
python# Python — palettes seaborn disponibles
# 'Blues', 'Blues_d', 'viridis', 'magma', 'tab10', 'Set2'
sns.set_palette('Set2')
# Couleur personnalisée (hex)
sns.barplot(data=df, x='dept', y='salaire', color='#FF6B35')r# R — couleurs manuelles
scale_fill_manual(values = c("#2196F3", "#FF5722", "#4CAF50"))
# ou palettes prêtes à l'emploi
scale_fill_brewer(palette = "Set2")Thèmes ggplot2
r# Les thèmes les plus utilisés
theme_minimal() # fond blanc, grille légère
theme_classic() # fond blanc, axes seulement
theme_bw() # fond blanc, cadre noir
theme_dark() # fond sombre🔗 Pont Excel → Python/R
Chaque graphique Excel a son équivalent direct :
| Graphique Excel | Python (seaborn/matplotlib) | R (ggplot2) |
|---|---|---|
| Histogramme | sns.histplot() |
geom_histogram() |
| Barres groupées | sns.barplot() |
geom_col() |
| Barres empilées | df.plot(kind='bar', stacked=True) |
geom_col(position='stack') |
| Courbe (ligne) | sns.lineplot() |
geom_line() |
| Nuage de points | sns.scatterplot() |
geom_point() |
| Camembert | plt.pie() |
geom_col() + coord_polar() |
| Boîte à moustaches | sns.boxplot() |
geom_boxplot() |
La grammaire de ggplot2 (à retenir) :
rggplot(data, aes(x = col_x, y = col_y, color = col_groupe)) +
geom_XXXX() + # type de graphique
labs(title = "...") + # étiquettes
theme_minimal() # style💡 En ggplot2, on ajoute des couches avec
+. Chaquegeom_est une couche visuelle. C'est plus verbeux qu'Excel mais infiniment plus flexible.
✏️ Mini-exercices
Exercice 1 — Python : barres horizontales par ancienneté
Crée un graphique en barres horizontales montrant l'ancienneté de chaque employé,
trié du plus ancier au plus récent. Titre : "Ancienneté des employés".
👉 Voir la réponse......
pythondf_tri = df.sort_values('anciennete', ascending=True)
plt.figure(figsize=(9, 7))
plt.barh(df_tri['nom'], df_tri['anciennete'], color='#2196F3')
plt.title('Ancienneté des employés', fontsize=13, fontweight='bold')
plt.xlabel('Ancienneté (années)')
plt.tight_layout()
plt.show()
# Bamba Koné apparaît en haut (12 ans), Soro Aminata et Touré Mariam en bas (0 an)Exercice 2 — R : boxplot salaires par département
En R avec ggplot2, crée un boxplot comparant la distribution des salaires pour chaque département.
Colorie chaque département d'une couleur différente.
👉 Voir la réponse......
rggplot(df, aes(x = departement, y = salaire, fill = departement)) +
geom_boxplot(outlier.color = "red", outlier.size = 3) +
labs(
title = "Distribution des salaires par département",
x = "Département",
y = "Salaire (FCFA)"
) +
theme_minimal() +
theme(legend.position = "none")
# Direction : dispersion énorme (950k à 1 800k)
# Finance : groupé entre 540k et 620k
# Commercial : le plus bas, entre 180k et 380kExercice 3 — Python : graphiques en grille (subplots)
Crée une figure avec 2 graphiques côte à côte :
- Gauche : histogramme des salaires
- Droite : camembert des types de contrat
👉 Voir la réponse......
pythonfig, (ax1, ax2) = plt.subplots(1, 2, figsize=(13, 5))
# Histogramme
ax1.hist(df['salaire'], bins=6, color='#2196F3', edgecolor='white')
ax1.set_title('Distribution des salaires')
ax1.set_xlabel('Salaire (FCFA)')
ax1.set_ylabel('Effectif')
# Camembert
contrats = df['contrat'].value_counts()
ax2.pie(contrats, labels=contrats.index, autopct='%1.0f%%',
colors=['#1565C0', '#42A5F5', '#90CAF9'])
ax2.set_title('Répartition des contrats')
fig.suptitle('Tableau de bord RH — Bamba & Associés', fontsize=14, fontweight='bold')
plt.tight_layout()
plt.savefig('dashboard_rh.png', dpi=150)
plt.show()📋 Cheat Sheet — Visualisation
Python — matplotlib / seaborn
| Graphique | Code |
|---|---|
| Histogramme | sns.histplot(df['col']) |
| Barres | sns.barplot(data=df, x='cat', y='val') |
| Boxplot | sns.boxplot(data=df, x='cat', y='val') |
| Scatter | sns.scatterplot(data=df, x='x', y='y', hue='cat') |
| Ligne | sns.lineplot(data=df, x='x', y='y') |
| Camembert | plt.pie(valeurs, labels=labels, autopct='%1.0f%%') |
| Titre | plt.title('Titre') |
| Axes | plt.xlabel('X') / plt.ylabel('Y') |
| Sauvegarder | plt.savefig('fichier.png', dpi=150) |
| Afficher | plt.show() |
| Grille 1×2 | fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12,5)) |
R — ggplot2
| Graphique | Code |
|---|---|
| Histogramme | geom_histogram(bins=10) |
| Barres | geom_col() |
| Boxplot | geom_boxplot() |
| Scatter | geom_point() |
| Ligne | geom_line() |
| Droite tendance | geom_smooth(method='lm', se=FALSE) |
| Titre | labs(title='...', x='...', y='...') |
| Style | theme_minimal() / theme_classic() |
| Sauvegarder | ggsave('fichier.png', dpi=150) |
| Facettes (grille) | facet_wrap(~ variable) |
🧠 Quiz de validation
Question 1 — Tu veux montrer la répartition des salaires (est-ce que les valeurs se concentrent entre 400k et 600k ?). Quel graphique choisir ?
a) Camembert
b) Histogramme
c) Nuage de points
d) Courbe
👉 Voir la réponse......
Réponse : b) Histogramme
L'histogramme est fait pour visualiser la distribution d'une variable numérique continue. Il montre où se concentrent les valeurs, si la distribution est symétrique ou asymétrique, et où se trouvent les outliers.
Question 2 — En ggplot2, comment ajoute-t-on un titre à un graphique ?
a) title("Mon titre")
b) ggplot(title = "Mon titre")
c) + labs(title = "Mon titre")
d) + theme(title = "Mon titre")
👉 Voir la réponse......
Réponse : c) + labs(title = "Mon titre")
En ggplot2, labs() gère toutes les étiquettes : title, subtitle, x, y, color, fill, caption. On l'ajoute comme une couche supplémentaire avec +.
Question 3 — Tu dois comparer la dispersion des salaires entre les CDI, CDD et Stagiaires pour détecter des inégalités. Quel graphique est le plus adapté ?
a) Barres (salaire moyen par contrat)
b) Camembert
c) Boîte à moustaches (boxplot)
d) Histogramme
👉 Voir la réponse......
Réponse : c) Boîte à moustaches
Le boxplot montre en même temps : médiane, Q1, Q3, outliers et étendue — pour chaque groupe. Un graphique en barres ne montre que la moyenne, cachant toute la dispersion. Le boxplot révèle si un groupe est homogène ou très hétérogène.
✅ Résumé du module
| Ce que tu as appris | Détail |
|---|---|
| Choisir le bon graphique | Histogramme, barres, boxplot, scatter, camembert |
| matplotlib | Graphiques de base, personnalisation, subplots |
| seaborn | Graphiques statistiques élégants en une ligne |
| ggplot2 | Grammaire des graphiques : aes + geom + labs + theme |
| Sauvegarder | plt.savefig() (Python) · ggsave() (R) |
| Pont Excel→Python/R | Chaque graphique Excel traduit en code |
⚡ Bonus — Packages qui génèrent tous les graphiques automatiquement
Comme pour les statistiques descriptives (M11), il existe des packages qui produisent des visualisations complètes en une ou deux lignes, sans coder graphique par graphique.
Python
| Package | Ce qu'il génère | Installation |
|---|---|---|
| plotly.express | Graphiques interactifs (zoom, survol) — une ligne par graphique | pip install plotly |
| ydata-profiling | Rapport HTML complet : stats + histogrammes + corrélations + outliers | pip install ydata-profiling |
| sweetviz | Rapport visuel HTML avec tous les graphiques de distribution | pip install sweetviz |
| dtale | Interface interactive dans le navigateur : graphiques à la demande | pip install dtale |
pandas .plot() |
Graphiques rapides directement depuis un DataFrame, sans import | inclus avec pandas |
python# plotly.express — graphique interactif en une ligne
import plotly.express as px
px.histogram(df, x='salaire', color='departement', title='Distribution des salaires')
px.box(df, x='contrat', y='salaire', title='Salaires par contrat')
px.scatter(df, x='anciennete', y='salaire', color='departement', size='salaire')
# pandas .plot() — le plus rapide, sans import supplémentaire
df['salaire'].plot(kind='hist', bins=6, title='Distribution des salaires')
df.groupby('departement')['salaire'].mean().plot(kind='bar', title='Salaire moyen par département')
# dtale — lance une interface interactive dans le navigateur
import dtale
dtale.show(df) # → ouvre un tableau de bord complet dans ton navigateurR
| Package | Ce qu'il génère | Installation |
|---|---|---|
| DataExplorer | Rapport HTML complet : distributions, corrélations, valeurs manquantes | install.packages("DataExplorer") |
| GGally | Pairplot (toutes les relations entre variables en une grille) | install.packages("GGally") |
| skimr | Résumé texte + mini-histogrammes dans la console | install.packages("skimr") |
r# DataExplorer — rapport HTML automatique
library(DataExplorer)
create_report(df, output_file = "rapport_rh.html")
# → génère un HTML avec : aperçu, distributions, corrélations, valeurs manquantes
# GGally — pairplot : toutes les variables vs toutes les variables
library(GGally)
ggpairs(df[, c("salaire", "anciennete")])
# skimr — résumé avec mini-histogrammes ASCII
library(skimr)
skim(df)Quand utiliser quoi ?
| Besoin | Outil recommandé |
|---|---|
| Explorer rapidement un nouveau dataset | ydata-profiling (Python) · DataExplorer (R) |
| Graphique interactif pour une présentation | plotly.express |
| Explorer librement dans le navigateur | dtale |
| Graphique rapide sans réfléchir | pandas .plot() |
| Toutes les relations entre variables | GGally::ggpairs() (R) |
| Graphique précis et personnalisé | seaborn / ggplot2 |
🎉 Acte IV terminé !
Tu as maintenant les bases de R & Python pour l'analyse de données :
- M10 — Environnements, installation, premiers pas
- M11 — Statistiques descriptives (pandas, dplyr, EDA rapide)
- M12 — Visualisation (matplotlib, seaborn, ggplot2, packages auto)
🚀 La suite — Mini-projet B & Projet Final
Mini-projet B — Dataset télécom (opérateur mobile ivoirien fictif)
Tu appliqueras Excel + SQL + Python/R sur des données simples de téléphonie : abonnés, consommations, forfaits.
Projet Final Niveau Débutant — Rapport complet RH ivoirien
Le projet de clôture qui valide l'ensemble du bootcamp niveau débutant.
Bootcamp Data Analyst — From Zero to Hero | Niveau Débutant · Acte IV