TP 5 – Explorer avant de prédire
Objectif : trouver 3 faits dans les données qui guideront nos modèles de l’après-midi.
Règle d’or : Spark ne dessine pas. On agrège (groupBy) ou on échantillonne (sample) dans Spark, puis
toPandas() sur un petit résultat, puis Matplotlib ou Seaborn.
Mise en place
Section intitulée « Mise en place »from pyspark.sql import SparkSession, functions as Fimport matplotlib.pyplot as pltimport seaborn as snssns.set_theme(style="whitegrid")
spark = SparkSession.builder.appName("TP").master("local[*]").getOrCreate()spark.sparkContext.setLogLevel("ERROR")zones = spark.read.csv("data/taxi_zone_lookup.csv", header=True, inferSchema=True)trips = (spark.read.parquet("data/trips.parquet") .withColumn("heure", F.hour("tpep_pickup_datetime")) .withColumn("jour_semaine", F.dayofweek("tpep_pickup_datetime")) # 1 = dimanche … 7 = samedi .join(zones.select(F.col("LocationID").alias("PULocationID"), "Borough"), "PULocationID"))trips.cache().count()1. Distribution des montants payés (total_amount) : histogramme
Section intitulée « 1. Distribution des montants payés (total_amount) : histogramme »Indice : créer une colonne tranche = floor(total_amount / 5) * 5, puis groupBy("tranche").count(), puis
sns.barplot. plt.xticks(rotation=90) pour lire les étiquettes.
2. Tarif du compteur (fare_amount) selon la distance : nuage de points sur un échantillon
Section intitulée « 2. Tarif du compteur (fare_amount) selon la distance : nuage de points sur un échantillon »Indice : trips.sample(fraction=0.03, seed=1), puis plt.scatter. Limitez les axes : 0 à 30 miles, 0 à 120 $.
C’est fare_amount (sans pourboire ni taxes) que nous prédirons au TP 6.
3. Courses par jour de semaine et par heure : heatmap
Section intitulée « 3. Courses par jour de semaine et par heure : heatmap »Indice : groupBy("jour_semaine", "heure").count(), puis toPandas().pivot(index=..., columns=..., values=...),
puis sns.heatmap.
4. Montant moyen par arrondissement de départ : barres
Section intitulée « 4. Montant moyen par arrondissement de départ : barres »groupBy("Borough").agg(F.avg("total_amount")), puis sns.barplot.
5. Vos 3 observations utiles pour prédire le montant d’une course
Section intitulée « 5. Vos 3 observations utiles pour prédire le montant d’une course »Regardez bien le nuage de points : que signifie la ligne horizontale ?
Bonus – le même nuage de points en Plotly (interactif)
Section intitulée « Bonus – le même nuage de points en Plotly (interactif) »pip install plotly, puis plotly.express.scatter(ech, x="trip_distance", y="fare_amount", opacity=0.3).
Correction
Section intitulée « Correction »# 1. Histogramme : Spark compte par tranche de 5 $, pandas dessinetranches = (trips.withColumn("tranche", (F.floor(F.col("total_amount") / 5) * 5).cast("int")) .groupBy("tranche").count().orderBy("tranche") .filter("tranche < 150").toPandas())sns.barplot(data=tranches, x="tranche", y="count", color="#3494BA")plt.xticks(rotation=90); plt.xlabel("Montant total ($, par tranche de 5)"); plt.ylabel("Courses")
# 2. Nuage sur un échantillon de 3 %ech = trips.sample(fraction=0.03, seed=1).select("trip_distance", "fare_amount").toPandas()plt.scatter(ech.trip_distance, ech.fare_amount, s=5, alpha=0.3)plt.xlim(0, 30); plt.ylim(0, 120); plt.xlabel("Distance (miles)"); plt.ylabel("Tarif ($)")
# 3. Heatmap : groupBy Spark → pivot pandascourses_jour_heure = (trips.groupBy("jour_semaine", "heure").count().toPandas() .pivot(index="jour_semaine", columns="heure", values="count").fillna(0))courses_jour_heure.index = ["Dim", "Lun", "Mar", "Mer", "Jeu", "Ven", "Sam"]sns.heatmap(courses_jour_heure, cmap="crest", cbar_kws={"label": "courses"})
# 4. Montant moyen par arrondissementpar_borough = (trips.groupBy("Borough") .agg(F.avg("total_amount").alias("montant_moyen"), F.count("*").alias("courses")) .orderBy(F.desc("montant_moyen")).toPandas())sns.barplot(data=par_borough, x="Borough", y="montant_moyen", color="#58B6C0")Observations attendues
Section intitulée « Observations attendues »- Le tarif est presque proportionnel à la distance… sauf un palier horizontal à 70 $ : le forfait JFK. Un modèle linéaire ratera ce palier ; un arbre le capturera.
- Deux pics de trafic, 8h et 18h : l’heure est une feature utile (demande, embouteillages).
- Les aéroports (Queens, EWR) ont les montants moyens les plus élevés, Manhattan le plus de courses : l’arrondissement de départ est une feature utile.
Pièges rencontrés en séance
Section intitulée « Pièges rencontrés en séance »| Symptôme | Cause | Solution |
|---|---|---|
| Le notebook rame, puis « Java heap space » | toPandas() sur tout trips | Agréger ou échantillonner avant |
| L’histogramme a des barres jusqu’à 400 $ illisibles | Quelques courses extrêmes | Filtrer tranche < 150 |
| Heatmap vide ou décalée | pivot sur les mauvaises colonnes | index="jour_semaine", columns="heure", values="count" |
ModuleNotFoundError: seaborn | Environnement virtuel non activé | pip install -r requirements.txt dans le venv |
- À mi-parcours, point d’étape collectif. Si vous avez terminé, passez au bonus Plotly.
- Un participant présente ses 3 observations. Les noter au tableau : elles serviront aux TP 6, 7 et 8.
- À retenir : les données parlent avant le modèle. Le palier à 70 $ décidera du choix de l’algorithme au TP 6.
Dépôt des participants : formations2026/formation-spark-ml (branche participants)
Contenu pédagogique © Ambient IT · 140 Avenue Jean Lolive, 93500 Pantin · formation@ambient-it.net · +33 (0)1 48 10 09 46
Organisme de formation enregistré sous le numéro 11 75 54743 75. Cet enregistrement ne vaut pas agrément de l'État.