Fichiers

Partie 5

Mini-projet

Le bilan de l'année pour la direction, puis la sauvegarde des résultats.

Étape 1 / 8
5.1
Lecture

La mission

La direction de la boutique vous demande un bilan de l'année 2025. Pour chaque question, utilisez la méthode que vous préférez (DataFrame ou SQL), en partant de ventes_propres et clients.

Cette fois, il n'y a plus de squelette de code : à vous de jouer ! Les indices et solutions restent disponibles.

5.2
Exercice

CA total et nombre de ventes

Quel est le chiffre d'affaires total de l'année, et combien de ventes ont été réalisées ?

À vous : complétez les « ... »
# À vous !
Besoin d'un indice ?

On peut utiliser agg directement sur le DataFrame, sans groupBy.

Voir la solution
Solution
ventes_propres.agg(F.round(F.sum("montant"), 2).alias("ca_total"),
                   F.count("*").alias("nb_ventes")).show()
Résultat attendu
CA total : 480625.2 € pour 5000 ventes
5.3
Exercice

Panier moyen par mode de paiement

Quel est le panier moyen (montant moyen d'une vente) pour chaque mode de paiement ?

À vous : complétez les « ... »
# À vous !
Besoin d'un indice ?

groupBy("mode_paiement") et F.avg("montant").

Voir la solution
Solution
(ventes_propres
 .groupBy("mode_paiement")
 .agg(F.round(F.avg("montant"), 2).alias("panier_moyen"), F.count("*").alias("nb_ventes"))
 .orderBy(F.desc("panier_moyen"))
 .show())
Résultat attendu
PayPal a le panier moyen le plus élevé : 99.32
5.4
Bonus

Le produit phare de chaque catégorie

Quel produit rapporte le plus dans chaque catégorie ?

Commencez par calculer le CA par couple (catégorie, produit). Ensuite, une fonction de fenêtre permet de numéroter les produits de chaque catégorie, du plus rentable au moins rentable, puis de garder le numéro 1.

Facultatif : à faire si vous le souhaitez
from pyspark.sql.window import Window

ca_produit = ventes_propres.groupBy("categorie", "produit").agg(...)

fenetre = Window.partitionBy("categorie").orderBy(F.desc("ca"))
ca_produit.withColumn("rang", F.row_number().over(fenetre)).filter(...).show()
Besoin d'un indice ?

Gardez les lignes où F.col("rang") == 1.

Voir la solution
Solution
from pyspark.sql.window import Window

ca_produit = (ventes_propres
              .groupBy("categorie", "produit")
              .agg(F.round(F.sum("montant"), 2).alias("ca")))

fenetre = Window.partitionBy("categorie").orderBy(F.desc("ca"))
(ca_produit
 .withColumn("rang", F.row_number().over(fenetre))
 .filter(F.col("rang") == 1)
 .drop("rang")
 .orderBy(F.desc("ca"))
 .show())
Résultat attendu
Bureau, Écran, Cafetière, Tapis de yoga et Livre de cuisine.
5.5
Guidé

Sauvegarder en Parquet

On enregistre le CA par catégorie et par mois au format Parquet : un format en colonnes, compressé, qui garde le schéma. C'est le format de référence avec Spark, bien plus efficace que le CSV.

mode("overwrite") remplace le résultat s'il existe déjà.

Tapez ce code dans une nouvelle cellule, puis exécutez-le
ca_cat_mois = (ventes_propres
               .groupBy("categorie", "mois")
               .agg(F.round(F.sum("montant"), 2).alias("ca"))
               .orderBy("categorie", "mois"))

ca_cat_mois.write.mode("overwrite").parquet("resultats/ca_categorie_mois")
Résultat attendu
Aucun affichage. Un dossier resultats/ca_categorie_mois vient d'être créé.
5.6
Exercice

Relire le fichier Parquet

Relisez le résultat avec spark.read.parquet(...), affichez son schéma et comptez ses lignes.

Allez aussi voir le dossier resultats/ca_categorie_mois : Spark n'a pas écrit un fichier, mais un dossier qui contient un fichier par partition.

À vous : complétez les « ... »
relu = spark.read.parquet(...)
relu.printSchema()
print(relu.count())
Besoin d'un indice ?

Le chemin est le même que celui utilisé pour l'écriture.

Voir la solution
Solution
relu = spark.read.parquet("resultats/ca_categorie_mois")
relu.printSchema()
print(relu.count())
Résultat attendu
3 colonnes (categorie, mois, ca) et 60 lignes : 5 catégories × 12 mois.
5.7
Bonus

Un graphique du CA par mois

Le CA par mois ne fait que 12 lignes : on peut le convertir en tableau pandas avec toPandas(), puis tracer un graphique. On ne fait jamais toPandas() sur un gros DataFrame non agrégé : tout serait rapatrié sur votre machine.

Facultatif : à faire si vous le souhaitez
import matplotlib.pyplot as plt

pdf = ca_mois.toPandas()
pdf.plot(x="mois", y="ca", kind="bar")
plt.show()
Besoin d'un indice ?

Le code est déjà complet : exécutez-le, puis ajoutez un titre avec plt.title(...).

Voir la solution
Solution
import matplotlib.pyplot as plt

pdf = ca_mois.toPandas()
pdf.plot(x="mois", y="ca", kind="bar", legend=False, color="#E25A1C", figsize=(8, 4))
plt.title("Chiffre d'affaires par mois (2025)")
plt.ylabel("CA (€)")
plt.tight_layout()
plt.show()
Résultat attendu
Un diagramme en barres ; novembre et décembre dépassent nettement les autres mois.
5.8
Guidé

Arrêter Spark

Bravo, vous avez terminé ! Pensez toujours à arrêter la session à la fin, pour libérer la mémoire.

Ce que vous avez appris :

NotionEn une ligne
SparkSessionle point d'entrée de toute application Spark
RDDmap, filter, flatMap, reduceByKey sur une collection distribuée
Lazy evaluationles transformations attendent qu'une action lance le calcul
DataFrameselect, filter, withColumn, orderBy
NettoyagedropDuplicates, fillna, isNull
AgrégationsgroupBy(...).agg(F.sum, F.avg, F.count)
Jointuresjoin(autre, on="cle", how="inner" / "left_anti")
Spark SQLcreateOrReplaceTempView puis spark.sql("SELECT ...")
Fichierswrite.parquet(...) et read.parquet(...)
Tapez ce code dans une nouvelle cellule, puis exécutez-le
spark.stop()
Résultat attendu
Aucun affichage.

Astuce : les flèches ← → du clavier permettent aussi de naviguer.