TP – Traitement des données en tables

Lecture

Dans ce TP nous allons travailler avec un fichier csv.

Nous utiliserons le module csv de la bibliothèque standard. (standard = pas de pip install).

Commencez par un dossier TP_data ensuite, téléchargez le fichier suivant dans votre dossier TP_data :

Maintenant, dans le même dossier créez le fichier tp_data contenant le code suivant :

# On importe le moduele csv
import csv
# On charge le fichier csv
data = open("db.csv", newline='')
# On le lit et le transforme en liste.
table = list(csv.reader(data, delimiter=';'))
# On affiche cette liste
print(table)

La fonction reader du module csv prend en argument un fichier ouvert et renvoie une valeur spéciale représentant un fichier CSV. Avec l’aide la  fonction list on convertie cela en tableau Python.

On remarque alors que la variable table contient un tableau de tableau de chaîne de caractères. Le première tableau contient :
['Id', 'Titre', 'Company', 'Note', 'Score', 'Durée', 'Sortie', 'Budget', "Weekend d'ouverture USA", 'USA', 'Monde']

Ce premier tableau est important, il contient les descripteurs ou attribus.

IdTitreCompanyNoteScoreDuréeSortieBudgetWeekend d’ouverture USAUSAMonde
1Iron ManMarvel7.979126200814000000098618668318604126585366247
2The Incredible HulkMarvel6.761112200815000000055414050134806913263427551
3Iron Man 2Marvel7571242010200000000128122480312433331623933331
4ThorMarvel757115201115000000065723338181030624449326618
5Captain America: The First AvengerMarvel6.966124201114000000065058524176654505370569774
6The AvengersMarvel86914320122200000002074387086233579101518812988

Vous pouvez afficher un peu mieux vos données avec cette simple boucle :

for ligne in table:
    print(ligne)

Quel est le contenu des variables table[1][1] et table[1][6], de quel type sont ces variables ?

Solution

Solution

'Iron Man'  et '2008'. Les deux variables sont des chaînes de caractères.

Ceci dit, cette structure de donnée n’est pas de plus pratiques… Une alternative est proposée par le module csv, la fonction DictReader.

import csv
# On charge le fichier csv
data = open("db.csv", newline='')
# On le lit et le transforme en liste.
table = list(csv.DictReader(data, delimiter=';'))

On obtient un tableau de dictionnaires ordonnés (Dans ces dictionnaires, les clés resteront dans l’ordre contrairement aux dictionnaires de base)

Pour accéder, par exemple à Iron man, on peut écrire : table[1]['Titre'] et l’année de sortie de ce film : table[1]['sortie']

Par contre, le type des données n’est pas celui qu’on souhaite, la date reste, par exemple, en string…  D’où l’exercice suivant :

Exercice :

Écrivez une fonction qui prend en entrée un dictionnaire comme ceux dans notre table et qui retourne un dictionnaire mais avec les bons types et qui vérifie que la note est bien comprise en 0 et 10. Ensuite appliquer cette fonction à toutes les lignes de la table.

map et dic.get

Solution

Cherchez avant de regarder

Solution

def validation(ligne):
    """Prend en entrée une ligne de la table
    et en retourne une copie valide"""
    identifiant = int(ligne['Id'])
    titre = ligne['Titre']
    company = ligne['Company']
    note = float(ligne['Note']) # Entre 0 et 10
    if note > 10 or note < 0:
        exit("Note invalide dans le fichier")
    score = int(ligne['Score']) # Entre 0 et 100
    duree = int(ligne['Durée']) # en minute
    sortie = int(ligne['Sortie']) # en année
    budget = int(ligne['Budget']) #en dollar
    week = int(ligne["Weekend d'ouverture USA"])
    usa = int(ligne['USA'])
    monde = int(ligne['Monde'])
    return {'Id' : identifiant,
            'Titre' : titre,
            'Company' : company,
            'Note' : note,
            'Score' : score,
            'Durée' : duree,
            'Sortie' : sortie,
            'Budget' : budget,
            "Weekend d'ouverture USA" : week,
            'USA' : usa,
            'Monde' : monde
           }

Maintenant appliquons cette fonction à chaque ligne.

table_valide = [validation(l) for l in table]

Quelques remarques :

Déjà, nous avons décidé de faire une copie de la table, nous aurions très bien pu faire une validation « en place », c’est à dire en modifiant la table originale.

Ici, on remarque que ligne[‘Score’] provoque une erreur si la clé score est absente du dictionnaire. Il existe une autre façon de faire : ligne.get('Score', 'pas de score') (https://www.tutorialspoint.com/python/dictionary_get.htm)

Et finalement, pour appliquer une fonction à chaque élément d’une liste il est pertinent d’avoir recours à map

:

table_valide = list(map(validation, table))

https://www.w3schools.com/python/ref_func_map.asp

Recherche

On souhaite interroger cette table et lui poser quelques questions, on appelle ces questions des requêtes.

Exercices :

Écrivez une fonction present(titre, table) qui permet de vérifier si un film est présent dans notre table, la recherche effectue à partir du titre.
Votre fonction doit réussir le tests suivants :

assert present("Iron Man", table) == True, 'pourtant il est présent'
assert present("Daredevil", table) == False, 'il ne se trouve pas dans la table'

Solution

Cherchez un peu avant

Solution

def present(titre, bdd):  
    for film in bdd:
        if film['Titre'] == titre:
            return True
    return False

Écrivez une requête qui permet de connaitre la note d’un film à partir de son titre.

Solution

Cherchez un peu avant

Solution

def note(titre, bdd):    
    for film in bdd:
        if film['Titre'] == titre:
            return film['Note']
    return None  # Ligne facultative.

Écrivez une requête qui retourne le titre des films sortie une année donnée.

Pour sortie_en(2018, table_valide) on attend :

['Black Panther', 'Avengers: Infinity War', 'Ant-Man and the Wasp', 'Aquaman']

Solution

Cherchez un peu avant

Solution

def sortie_en(annee, bdd):
    reponse = []
    for film in bdd:
        print
        if film['Sortie'] == annee:
            reponse.append(film["Titre"])
    return reponse

Écrivez une requête qui retourne la note moyenne des films de la table.

Solution

Cherchez un peu avant

Solution

def moyenne(bdd):
    somme = 0
    for film in bdd:
        somme += film['Note']
    return round(somme / len(bdd), 1)

round(nombre, n) permet d’arrondir à n chiffre après la virgule

Écrivez une requête qui retourne le film ayant fait le meilleur Weekend d’ouverture aux USA.

Solution

Cherchez un peu avant

Solution

def meilleur_weekend(bdd):
    maxi = 0
    for film in bdd:
        if film["Weekend d'ouverture USA"] > maxi:
            maxi = film["Weekend d'ouverture USA"]
            titre = film['Titre']
    return titre

Écrivez une requête qui retourne la note moyenne d’une compagny donnée (Marvel ou DC). Comparer ces notes.

Solution

Cherchez un peu avant

Solution

def marvel_vs_dc(bdd):
    dc = 0
    dc_somme = 0
    marvel =0
    marvel_somme = 0
    for film in bdd:
        if film['Company'] == 'Marvel':
            marvel += 1
            marvel_somme += film['Note']
        if film['Company'] == 'DC':
            dc += 1
            dc_somme += film['Note']
    return round(dc_somme / dc, 1), round(marvel_somme / marvel, 1)

Sans surprise c’est Marvel qui l’emporte.

Analyse de données

Dans cette partie nous utiliserons le module mathplotlib. Une introduction est disponible ici : https://codesturm.eu/2020/04/05/matplotlib/

L’objectif est de tracer quelques courbes pour faire apparaître certaines tendances.

Ici, il s’agit plus d’une démonstration de ce qu’on peut faire avec un jeu de données et la bibliothèque matplotlib

Voici un exemple permettant de comparer les budgets de Marvel et de DC.

from matplotlib import pyplot
dc = 0
marvel = 0
for film in table_valide:
    if film['Company'] == 'Marvel': 
        marvel += film['Budget']
    if film['Company'] == 'DC':
        dc += film['Budget']

pyplot.figure(figsize = (10, 10))
x = [marvel, dc]
pyplot.pie(x, labels = ['Marvel', 'DC'],
           colors = ['red', 'green'],
           explode = [0, 0],
           autopct = lambda x: str(round(x, 2)) + '%',
           pctdistance = 0.5, labeldistance = 0.4,
           shadow = True)
pyplot.title('Budget total')
pyplot.legend()

Un autre exemple :

notes_marvel = []
notes_cd = []
for film in table_valide:
    if film['Company'] == 'Marvel': 
        notes_marvel.append(film['Note'])
    if film['Company'] == 'DC':
        notes_cd.append(film['Note'])
pyplot.title('Évolution des notes')

graphe1, = pyplot.plot(
    [i for i in range(len(notes_marvel))],
    notes_marvel,
    color = 'red',
    linewidth = 2,
    markerfacecolor = 'blue',
    markersize = 5
    )
graphe2, = pyplot.plot(
    [i for i in range(len(notes_cd))],
    notes_cd,
    color = 'blue',
    linewidth = 2,
    markerfacecolor = 'blue',
    markersize = 5
    )

# lable des axes
pyplot.xlabel('Films')
pyplot.ylabel('Notes')
#Affichage d'une légende
pyplot.legend([graphe1, graphe2], ['Marvel', 'DC'])
plt.grid()
plt.show()

A vous d’imaginer comment représenter et exploiter ces données…
Dans un prochain TP nous travaillerons sur un jeu de données plus conséquent et nous ferons appel à pandas.