Fichiers

Partie 2

Les DataFrames

Charger un fichier CSV, l'explorer, filtrer et créer des colonnes.

Étape 1 / 12
2.1
Lecture

C'est quoi un DataFrame ?

Un DataFrame est une table distribuée : des lignes et des colonnes, chaque colonne ayant un nom et un type (entier, texte, date…). L'ensemble des noms et types s'appelle le schéma.

C'est l'outil que l'on utilise le plus avec Spark aujourd'hui : plus simple que les RDD, et optimisé automatiquement. Si vous connaissez pandas ou SQL, vous serez en terrain connu.

Dans la suite, on désigne une colonne avec F.col("nom_de_la_colonne").

2.2
Guidé

Charger les ventes

On lit le fichier CSV des ventes.

  • header=True : la première ligne contient les noms des colonnes ;
  • inferSchema=True : Spark devine le type de chaque colonne (sans cela, tout serait du texte).

printSchema() affiche le nom et le type de chaque colonne.

Tapez ce code dans une nouvelle cellule, puis exécutez-le
ventes = spark.read.csv("data/ventes.csv", header=True, inferSchema=True)
ventes.printSchema()
Résultat attendu
root
 |-- id_vente: integer (nullable = true)
 |-- date_vente: date (nullable = true)
 |-- id_client: integer (nullable = true)
 |-- produit: string (nullable = true)
 |-- categorie: string (nullable = true)
 |-- quantite: integer (nullable = true)
 |-- prix_unitaire: double (nullable = true)
 |-- mode_paiement: string (nullable = true)
2.3
Guidé

Regarder les premières lignes

show(5) affiche les 5 premières lignes sous forme de tableau, et count() compte les lignes.

Tapez ce code dans une nouvelle cellule, puis exécutez-le
ventes.show(5)
print("Nombre de ventes :", ventes.count())
Résultat attendu
Un tableau de 5 lignes, puis : Nombre de ventes : 5025
2.4
Guidé

Quelques statistiques

describe calcule rapidement le nombre de valeurs, la moyenne, l'écart-type, le minimum et le maximum des colonnes demandées.

Regardez la ligne count : la colonne quantite a moins de valeurs que prix_unitaire. Il y a donc des valeurs manquantes. Nous y reviendrons dans la partie 3.

Tapez ce code dans une nouvelle cellule, puis exécutez-le
ventes.describe("quantite", "prix_unitaire").show()
Résultat attendu
count : 4927 pour quantite, 5025 pour prix_unitaire
2.5
Exercice

Choisir des colonnes : select

Affichez seulement les colonnes produit, quantite et prix_unitaire, pour les 10 premières lignes.

À vous : complétez les « ... »
ventes.select(...).show(10)
Besoin d'un indice ?

select prend les noms des colonnes, séparés par des virgules.

Voir la solution
Solution
ventes.select("produit", "quantite", "prix_unitaire").show(10)
Résultat attendu
Un tableau de 10 lignes avec 3 colonnes.
2.6
Exercice

Filtrer des lignes : filter

Combien y a-t-il de ventes dans la catégorie Sport ?

À vous : complétez les « ... »
nb_sport = ventes.filter(...).count()
print(nb_sport)
Besoin d'un indice ?

La condition s'écrit F.col("categorie") == "Sport".

Voir la solution
Solution
nb_sport = ventes.filter(F.col("categorie") == "Sport").count()
print(nb_sport)
Résultat attendu
1011
2.7
Exercice

Combiner deux conditions

Trouvez les ventes où la quantité est d'au moins 3 et où le client a payé par Carte. Combien y en a-t-il ?

Pour combiner des conditions : & veut dire « et », | veut dire « ou ». Chaque condition doit être entre parenthèses.

À vous : complétez les « ... »
grosses_cartes = ventes.filter((...) & (...))
print(grosses_cartes.count())
Besoin d'un indice ?

(F.col("quantite") >= 3) & (F.col("mode_paiement") == "Carte")

Voir la solution
Solution
grosses_cartes = ventes.filter((F.col("quantite") >= 3) & (F.col("mode_paiement") == "Carte"))
print(grosses_cartes.count())
Résultat attendu
615
2.8
Guidé

Créer une colonne : withColumn

withColumn("nom", expression) ajoute une colonne (ou la remplace si elle existe déjà). Ici, on s'assure que date_vente est bien une date, puis on en extrait le mois.

Important : un DataFrame ne se modifie jamais. withColumn renvoie un nouveau DataFrame : on le range à nouveau dans la variable ventes.

Tapez ce code dans une nouvelle cellule, puis exécutez-le
ventes = (ventes
          .withColumn("date_vente", F.to_date("date_vente"))
          .withColumn("mois", F.month("date_vente")))

ventes.select("id_vente", "date_vente", "mois").show(5)
Résultat attendu
Un tableau avec une nouvelle colonne mois (de 1 à 12).
2.9
Exercice

Calculer le montant de chaque vente

Ajoutez à ventes une colonne montant égale à quantite × prix_unitaire, arrondie à 2 décimales.

Cette colonne servira jusqu'à la fin du TP : pensez bien à écrire ventes = ....

À vous : complétez les « ... »
ventes = ventes.withColumn("montant", ...)
ventes.select("produit", "quantite", "prix_unitaire", "montant").show(5)
Besoin d'un indice ?

F.round(F.col("quantite") * F.col("prix_unitaire"), 2)

Voir la solution
Solution
ventes = ventes.withColumn("montant", F.round(F.col("quantite") * F.col("prix_unitaire"), 2))
ventes.select("produit", "quantite", "prix_unitaire", "montant").show(5)
Résultat attendu
Par exemple : Livre de cuisine | 2 | 25.0 | 50.0
2.10
Exercice

Trier : orderBy

Affichez les 5 ventes les plus chères (le plus grand montant en premier).

À vous : complétez les « ... »
ventes.orderBy(...).show(5)
Besoin d'un indice ?

F.desc("montant") trie dans l'ordre décroissant.

Voir la solution
Solution
ventes.orderBy(F.desc("montant")).show(5)
Résultat attendu
Le montant le plus élevé est 995.0 (5 bureaux à 199 €).
2.11
Exercice

Les valeurs distinctes

Affichez la liste des catégories différentes, puis celle des modes de paiement différents. Que remarquez-vous dans les modes de paiement ?

À vous : complétez les « ... »
ventes.select(...).distinct().show()
ventes.select(...).distinct().show()
Besoin d'un indice ?

Mettez "categorie" dans le premier select, "mode_paiement" dans le second.

Voir la solution
Solution
ventes.select("categorie").distinct().show()
ventes.select("mode_paiement").distinct().show()
Résultat attendu
5 catégories. Pour les paiements : Carte, PayPal, Virement… et NULL, c'est-à-dire des valeurs manquantes.
2.12
Bonus

Petit, moyen ou gros panier

Créez une colonne taille_panier qui vaut "petit" si le montant est inférieur à 30, "moyen" s'il est inférieur à 100, et "gros" sinon. Comptez ensuite les ventes de chaque taille.

Facultatif : à faire si vous le souhaitez
paniers = ventes.withColumn("taille_panier", ...)
paniers.groupBy("taille_panier").count().show()
Besoin d'un indice ?

F.when(condition, valeur).when(condition, valeur).otherwise(valeur)

Voir la solution
Solution
paniers = ventes.withColumn(
    "taille_panier",
    F.when(F.col("montant") < 30, "petit")
     .when(F.col("montant") < 100, "moyen")
     .otherwise("gros"))
paniers.groupBy("taille_panier").count().show()
Résultat attendu
gros : 1243, moyen : 2097, petit : 1685

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