Aller au contenu

TP 5 – Explorer avant de prédire

  • 35 min · 9h55 – 10h30
  • Notebook : jour2/TP5_explorer.ipynb
  • Données : data/trips.parquet, data/taxi_zone_lookup.csv

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.

Réussi si : 4 graphiques affichés et 3 observations écrites.
from pyspark.sql import SparkSession, functions as F
import matplotlib.pyplot as plt
import seaborn as sns
sns.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).

# 1. Histogramme : Spark compte par tranche de 5 $, pandas dessine
tranches = (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 pandas
courses_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 arrondissement
par_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")
  1. 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.
  2. Deux pics de trafic, 8h et 18h : l’heure est une feature utile (demande, embouteillages).
  3. 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.
SymptômeCauseSolution
Le notebook rame, puis « Java heap space »toPandas() sur tout tripsAgréger ou échantillonner avant
L’histogramme a des barres jusqu’à 400 $ illisiblesQuelques courses extrêmesFiltrer tranche < 150
Heatmap vide ou décaléepivot sur les mauvaises colonnesindex="jour_semaine", columns="heure", values="count"
ModuleNotFoundError: seabornEnvironnement 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.