**TABLES DE DONNEES ET FORMAT CSV**

On travaillera ici sur un exemple : les notes en sciences de la classe BD :

Nom Prénom maths physique SVT
Dalton Averell 12 8 10
Maltese Corto 15 14 12
Lucky Luke 12 9 17
Talon Achile 20 17 6
Duck Donald 7 11 16

Le tableau ci-dessus a été enregistré au format csv dans le fichier "notes_en_sciences.csv".
Ouvrez et observez ce fichier dans un éditeur de texte (par exemple notepad++ ou bloc-note) puis dans un tableur.

CSV : Comma-Separated Values, est un format de texte représentant les données d'un tableau sous forme de chaînes de caractères séparées par des virgules.

Un fichier CSV est un fichier texte dans lequel chaque ligne de texte représente une ligne d'un tableau.
Les valeurs dans la ligne sont séparées par des virgules.

Le séparateur par défaut est la virgule. Toutefois, il est fréquent de rencontrer le point-virgule comme séparateur, voire même un espace ou une tabulation.

Python et les fichiers csv : La bibliothèque standard de python contient le module csv qui propose des fonctions permettant de lire et enregistrer facilement des fichiers au format csv.

1) Lecture du fichier

In [ ]:
import csv                                      # import du module (ou bilibothèque) csv
In [ ]:
fichier_csv = open('notes_en_sciences.csv',"r") # Ouverture du fichier csv en mode lecture (r pour "read")
reader_notes = csv.reader(fichier_csv)          # Création de l'itérateur reader qui va permettre
for ligne in reader_notes:                      #          le parcours du fichier ligne par ligne
    print(ligne)                                # Chaque ligne est une liste   
fichier_csv.close()                             # Fermeture du fichier (à ne pas oublier)

L'utilisation de with permet d'utiliser un protocole qui gère automatiquement la fermeture du fichier, même si un erreur survient. La séquence précédente devient alors :

In [ ]:
with open('notes_en_sciences.csv', "r") as fichier_csv:
    reader_notes = csv.reader(fichier_csv)          
    for ligne in reader_notes:  
        print(ligne) 

Si le séparateur n'est pas la virgule, comme c'est le cas dans le fichier "notes_point_virgule.csv", on n'obtient pas le résultat escompté :

In [ ]:
with open('notes_point_virgule.csv', "r") as fichier_csv:
    reader_notes = csv.reader(fichier_csv)          
    for ligne in reader_notes:  
        print(ligne, "nombre d'éléments", len(ligne)) 

Comme python ne trouve pas de virgule dans les lignes, il considère que chaque ligne est réduite à une seule grande chaine de caractères.

On peut cependant indiquer le séparateur à utiliser avec l'argument delimiter.

In [ ]:
with open('notes_point_virgule.csv', "r") as fichier_csv:
    reader_notes = csv.reader(fichier_csv, delimiter=';')          
    for ligne in reader_notes:  
        print(ligne, "nombre d'éléments", len(ligne)) 

2) Chargement de la table

Complétez la fonction lire_fichier_csv(nom_fichier) afin qu'elle renvoie la table (liste des lignes) contenue dans le fichier "notes_en_sciences.csv". Retour attendu:
[['Dalton', 'Averell', '12', '8', '10'], ['Maltese', 'Corto', '15', '14', '12'], ['Lucky', 'luke', '12', '9', '17'], ['Talon', 'Achile', '20', '17', '6'], ['Duck', 'Donald', '7', '11', '16']]

In [ ]:
def lire_fichier_csv(nom_fichier):
    """Votre code"""

##tests
table_notes = lire_fichier_csv("notes_en_sciences.csv")
print(table_notes)

Complétez la fonction afficher_table(table) afin qu'elle affiche de manière plus lisible la table.

Retour attendu : Dalton Averell 12 8 10 Maltese Corto 15 14 12 Lucky luke 12 9 17 Talon Achile 20 17 6 Duck Donald 7 11 16
In [ ]:
def affiche_table(table):
    """Votre code"""

##tests
affiche_table(table_notes)

3) Recherche d'une ligne

Complétez la fonction cherche_eleve(table, nom_eleve) qui renvoie la ligne correspondant à un élève.
Retour attendu :
['Talon', 'Achile', '20', '17', '6']

In [ ]:
def cherche_eleve(table, nom_eleve):
    """Votre code"""

##tests
ligne_talon = cherche_eleve(table_notes, "Talon")
print(ligne_talon)

4) Recherche d'un élément de la table et modification d'un élément de la table

Complétez la fonction cherche_note_math(table,nom_eleve) qui renvoie la note de math d'un élève.

In [ ]:
def cherche_note_math(table, nom_eleve):
    """Votre code"""

##tests
affiche_table(table_notes)
note_math_Lucky = cherche_note_math(table_notes, "Lucky")
print("La note de math de Lucky est",note_math_Lucky)

Complétez la fonction change_prenom(table,nom_eleve, nouveau_prenom) qui met à jour le prénom d'un élève.

In [ ]:
def change_prenom(table, nom_eleve, nouveau_prenom):
    """Votre code"""

##tests
print("Avant changement de prénom pour Duck :", cherche_eleve(table_notes, "Duck"))
change_prenom(table_notes, "Duck", "Daisy")
print("Après changement de prénom pour Duck :", cherche_eleve(table_notes, "Duck"))

Complétez la fonction augmente_un_note_math(table,nom_eleve) qui augmente de 1 point la note de math d'un élève.

In [ ]:
def augmente_un_note_math(table, nom_eleve):
    """Votre code"""

##tests
print("Avant augmentation pour Duck :", cherche_eleve(table_notes, "Duck"))
augmente_un_note_math(table_notes, "Duck")
print("Après augmentation pour Duck :", cherche_eleve(table_notes, "Duck"))
print("Avant augmentation pour Talon :", cherche_eleve(table_notes, "Talon"))
augmente_un_note_math(table_notes, "Talon")
print("Après augmentation pour Talon :", cherche_eleve(table_notes, "Talon"))

5) Conversion des valeurs

Lors de l'import d'un fichier csv toutes les valeurs sont de type chaîne de caractères.
Ces chaînes de caractères peuvent toutefois contenir une information de type entier, décimal, date, heure, booléen, couleur, ...
Dans l'exemple ci-dessus vous avez dû convertir la chaîne en entier pour pouvoir ajouter 1.
Pour pouvoir travailler avec notre table nous allons après le chargement de celle-ci convertir toutes les notes en entiers.

Complétez la fonction convertir_ligne(ligne) qui convertit les notes d'un élève au type int.

In [ ]:
def convertir_ligne(ligne):
    """Votre code"""

##tests
## rechargement de la table pour le test
table_notes = lire_fichier_csv("notes_en_sciences.csv")
ligne_talon = cherche_eleve(table_notes, "Talon")
print("Avant conversion pour Talon :", ligne_talon)
convertir_ligne(ligne_talon)
ligne_talon = cherche_eleve(table_notes, "Talon")
print("Après conversion pour Talon :", ligne_talon)

Complétez la fonction convertir_table(table) qui modifie la table en convertissant chacune de ses lignes.

In [ ]:
def convertir_table(table):
    """Votre code"""

##tests
## rechargement de la table pour le test
table_notes = lire_fichier_csv("notes_en_sciences.csv")
print("Avant conversion :\n", table_notes)
convertir_table(table_notes)
print("Après conversion :\n", table_notes)

6) Enregistrer un table

Complétez la fonction enregistre(table, nom_fichier) qui enregistre la table au format csv. Le module csv fournit un reader pour la lecture d'un fichier csv, de la même manière il fournit un writer pour l'écriture dans un fichier. On pourra consulter la page suivante : module csv ou consulter l'aide avec un help(csv.writer)

In [ ]:
def enregistre_fichier_csv(table, nom_fichier):
    """Votre code"""

#tests
table_notes = lire_fichier_csv("notes_en_sciences.csv")
print("Table initiale :")
affiche_table(table_notes)
augmente_un_note_math(table_notes, "Lucky")
change_prenom(table_notes, "Duck", "Daisy")
enregistre_fichier_csv(table_notes,"test_enregistrement.csv")
table_enregistree = lire_fichier_csv("test_enregistrement.csv")
print("Table enregistrée :")
affiche_table(table_enregistree)

7) Recherche de plusieurs lignes dans la table

Complétez la fonction table_forts_en_physique(table) qui renvoie la liste (éventuellement vide) des élèves qui ont la moyenne en physique. Retour attendu :
[['Maltese', 'Corto', 15, 14, 12], ['Talon', 'Achile', 20, 17, 6], ['Duck', 'Donald', 7, 11, 16]]

In [ ]:
def table_forts_en_physique(table):
    """Votre code"""

#test
table_notes = lire_fichier_csv("notes_en_sciences.csv")
convertir_table(table_notes)
print("Ont la moyenne en physique :", table_forts_en_physique(table_notes))

Complétez la fonction table_forts_en_MP(table) qui renvoie la liste (éventuellement vide) des élèves qui ont la moyenne à la fois en math et en physique. Retour attendu : [['Maltese', 'Corto', 15, 14, 12], ['Talon', 'Achile', 20, 17, 6]]

In [ ]:
def table_forts_en_MP(table):
    """Votre code"""

#test
table_notes = lire_fichier_csv("notes_en_sciences.csv")
convertir_table(table_notes)
print("Ont la moyenne en maths et en physique :", table_forts_en_MP(table_notes))

Complétez la fonction table_pas_moyenne_partout(table) qui renvoie la liste constituée uniquement des élèves qui n’ont pas la moyenne dans au moins l’une des trois disciplines.

Retour attendu : [['Dalton', 'Avrel', 12, 8, 10], ['Lucky', 'luke', 12, 9, 17], ['Talon', 'Achile', 20, 17, 6], ['Duck', 'Donald', 7, 11, 16]]

In [ ]:
def table_pas_moyenne_partout(table):
    """Votre code"""

#test
print("Tous les élèves :")
affiche_table(table_notes)
print("Elèves n'ayant pas la moyenne partout :")
affiche_table(table_pas_moyenne_partout(table_notes))

8) Trier une table suivant une colonne

On souhaite pouvoir trier les élèves suivant une colonne.

Python propose deux fonctions qui permettent de trier des listes :

  • La fonction sorted(une_liste) qui renvoie une copie triée dans l'ordre croissant de liste une_liste.
  • La méthode une_liste.sort() qui trie dans l'ordre croisssant la liste une_liste, en la modifiant.

On peut passer à sort ou à sorted un argument key=une_fonction. La liste est alors triée selon les valeurs renvoyées par une_fonction quand on l'applique à chacun des éléments de la liste. Complétez la fonction note_math(ligne) qui renvoie la note de math de l'élève d'une ligne donnée et permettra ainsi de trier les élèves dans l'ordre croissant des notes de math.

In [ ]:
def note_math(ligne):
    """Votre code"""


##test
table_notes = lire_fichier_csv("notes_en_sciences.csv")
convertir_table(table_notes)
table_notes.sort(key=note_math)
print("Elèvess triés dans l'ordre croissant des notes de math :")
affiche_table(table_notes)

On peut aussi trier des listes dans l'ordre décroissant en utilisant l'argument reverse=True. Ecrire un script qui affiche les élèves dans l'ordre alphabétique décroissant.

In [ ]:
"""Votre code"""

9) Fusionner deux tables

On dispose d'un second fichier "notes_lettres.csv" contenant les notes des élèves en Français et en Histoire. On souhaite pouvoir regrouper les notes dans une même table. Complétez la fonction fusion(table1, table2) qui renvoie la nouvelle table obtenue en fusionnant deux tables de notes.

In [ ]:
def fusionne_tables(table1, table2):
    """Votre code"""

##test
table_notes1 = lire_fichier_csv("notes_en_sciences.csv")
print("Notes en sciences :")
affiche_table(table_notes1)
table_notes2 = lire_fichier_csv("notes_en_lettres.csv")
print("Notes en lettres :")
affiche_table(table_notes2)
print("Fusion des deux tables :")
affiche_table(fusionne_tables(table_notes1, table_notes2))

10) Tester si les données de la table sont valides

Quand beaucoup de données sont saisies par différentes personnes, des erreurs peuvent se produire. Il faut pouvoir les détecter pour éventuellement les corriger. On dispose d'un autre fichier de notes "notes_annee_precedente.csv". Exécutez le code ci-dessous.

In [ ]:
table_notes = lire_fichier_csv("notes_annee_precedente.csv")
convertir_table(table_notes)
augmente_un_note_math(table_notes, "Maltese")
print("Note de math de Maltese :", cherche_note_math(table_notes, "Maltese"))
table_notes.sort(key=note_math)
print("Note de math de Maltese :", cherche_note_math(table_notes, "Maltese"))

Il y a un problème avec la table. Affichons-la :

In [ ]:
table_notes = lire_fichier_csv("notes_annee_precedente.csv")
affiche_table(table_notes)

La table comporte des doublons. C'est un problème car si on veut modifier des valeurs pour Maltese, on risque de ne le faire que dans une seule ligne. Après plusieurs manipulations de la table, quelles valeurs ressortiront ? C'est parfois difficile à prévoir. Complétez la fonction doublons(table_notes) qui renvoie la liste des élèves apparaissant plus d'une fois dans la table. Retour attendu: ['Maltese', 'Talon']

In [ ]:
def doublons(table_notes):
    """Votre Code"""

##tests
table_notes = lire_fichier_csv("notes_annee_precedente.csv")
print(doublons(table_notes))

Un autre problème peut venir aussi de notes mal saisies. Complétez la fonction note_coherente(note_str) qui renvoie True si la chaine de caractères note_str contient bien une note entière comprise au sens large entre 0 et 20.

In [ ]:
def note_coherente(note_str):
    """Votre Code"""

##tests
print(note_coherente("17"))
print(note_coherente("4,5"))
print(note_coherente("-2"))
print(note_coherente("18"))
print(note_coherente("1a"))
print(note_coherente("33"))

Complétez la fonction notes_incoherentes(table_notes) qui renvoie la lite des élèves de la table ayant des notes incohérentes. Retour attendu: [['Dalton', 'Averell', '13', '91', '11'], ['Lucky', 'luke', '7', '7', '77']]

In [ ]:
def notes_incoherentes(table_notes):
    """Votre Code"""

##tests
table_notes = lire_fichier_csv("notes_annee_precedente.csv")
affiche_table(table_notes)
print(notes_incoherentes(table_notes))

Le choix du traitement à appliquer aux doublons ou aux valeurs incohérentes n'est pas une question simple. Il dépend souvent du type de données étudiées.