Vous pouvez me contacter via Facebook pour questions & suggestions :
Page Facebook relative à mon site
Dans le chapitre 11 je vous ai montré comment manipuler des fichiers TXT (données non structurées). Python est capable aussi de manipuler des fichiers de données structurées (au format CSV ou JSON) via la bibliothèque pandas.
Avant d'aborder la bibliothèque pandas je veux vous montrer que l'on peut effectuer des traitements basiques sur les fichiers CSV & JSON grâce à deux modules pré-installés.
Le sigle CSV signifie 'comma separated values' qui veut dire 'valeurs séparées par des virgules'. Il définit un format de fichier pour l'échange de données tabulaires c'est à dire de données provenant d'un tableur.
Je dispose d'une feuille de calcul réalisée avec calc de libre Office (ce pourrait être un classeur Excel).
J'ai besoin de ces données pour un traitement via Python.
Je dois d'abord enregistrer le classeur dans un fichier CSV à partir de Calc.
Commande : Fichier/Enregistrez sous / type : texte csv , nom : bareme.csv
Ce fichier CSV est enregistré dans c :/python_prog sous le nom "bareme.csv".
Lorsque j'ai créé ce fichier, Calc m'a demandé quel délimiteur je voulais comme délimiteur de champs ;
j'ai répondu la virgule.
référence,désignation ,prix ht bo 001,boulons de 7 par 100,5 bo 0002,boulons de 8 par 100,6 bo 0003,boulons de 9 par 100,8 cl 001,clous 50mm par 100,4 cl 002,clous 70mm par 100,5
>>> import csv
>>> import os
>>> os.chdir("c:/python_prog") #chgt de directory
>>> fichier =open('bareme.csv','r')
>>> contenu =csv.reader(fichier,delimiter =',')
>>> for ligne in contenu:
... print(ligne) #affichage de toutes les colonnes du tableau
...
['référence', 'désignation ', 'prix ht']
['bo 001', 'boulons de 7 par 100', '5']
['bo 0002', 'boulons de 8 par 100', '6']
['bo 0003', 'boulons de 9 par 100', '8']
['cl 001', 'clous 50mm par 100', '4']
['cl 002', 'clous 70mm par 100', '5']
>>> for ligne in contenu:
... print(ligne[0], ligne[2]) #affichage des colonnes 'références' et 'prix ht'
référence prix ht
bo 001 5
bo 0002 6
bo 0003 8
cl 001 4
cl 002 5
>>>
Il faut importer le module csv qui permet de manipuler les fichiers CSV.
Il faut aussi importer le module os pour disposer de la fonction chdir() qui permet de changer de répertoire courant.
Le fichier "bareme.csv" est ouvert en lecture (mode : "r").
Le contenu du fichier est récupéré avec la méthode reader() appliquée à l'objet de type file.
Cette méthode permet de récupérer le contenu du fichier sous forme de listes à raison d'un liste par ligne ; la première
liste correspond aux en-têtes de colonne.
Avec une boucle on peut parcourir toutes les listes.
On peut afficher seulement certaines colonnes sachant que la première colonne a l'indice 0.
On peut récupérer le contenu d'un fichier CSV sous forme de dictionnaires.
>>> fichier =open('bareme.csv','r')
>>> dicos = csv.DictReader(fichier,delimiter =',')
>>> for dico in dicos :
... print(dico)
...
{'référence': 'bo 001', 'désignation ': 'boulonsde 7 par 100', 'prix ht': '5'}
{'référence': 'bo 0002', 'désignation ': 'boulons de 8 par 100', 'prix ht': '6'}
{'référence': 'bo 0003', 'désignation ': 'boulons de 9 par 100', 'prix ht': '8'}
{'référence': 'cl 001', 'désignation ': 'clous 50mm par 100', 'prix ht': '4'}
{'référence': 'cl 002', 'désignation ': 'clous 70mm par 100', 'prix ht': '5'}
Pour récupérer un fichier CSV sous forme de dictionnaires il faut utiliser la fonction DictReader().
Pour chaque ligne du fichier CSV d'origine on obtient un dictionnaire.
Comme le fichier d'origine avait trois colonnes, chaque dictionnaire comprend trois paires de clé:valeur.
Les ent-têtes de colonnes deviennent les clés dans chaque dictionnaire.
Nous pouvons bien sûr créer un fichier CSV à partir d'une liste de listes.
Le script :
#nom programme : fichier_csv_ecrire.py
#objet : écrire dans un fichier csv
import csv
listes = [ ['id', 'Nom', 'Age', 'Taille'] ,
[1, 'alain', 19, 180],
[2, 'bernard', 30, 185],
[3, 'claude', 27, 175] ]
with open('donnees.csv', 'w') as fichier:
contenu= csv.writer(fichier, delimiter=',')
for ligne in listes:
contenu.writerow(ligne)
print("fichier crée")
On crée le fichier "donnees.csv' à partir d'une liste de listes ; la première liste tient lieu d'en-têtes.
Toutes les sous-listes ont la même structure : id, nom, âge, taille.
id,Nom,Age,Taille 1,alain,19,180 2,bernard,30,185 3,claude,27,175
Remarque importante : ouverture en mode "w" ; donc si le fichier existe il est écrasé et s'il n'existe pas il est créé.
Pour écrire dans un fichier CSV il faut utiliser les méthodes writer() & writerow()
La première méthode a pour argument l'objet "file" et produit un objet "contenu".
La deuxième méthode appliquée à l'objet "contenu" permet d'écrire une ligne dans le fichier.
JSON (JavaScript Object Notation) est un format de données standard utilisé pour représenter et stocker des données structurées constitués d'items (paires clé-valeur), donc similaire à un dictionnaire Python.
Ce format initié d'abord pour le langage JavaScript est maintenant devenu un standard indépendant de ce langage.
Fichier créé avec l'application "Bloc-notes" et nommé "fiche.json".
{"nom": "Allemand",
"prenom" : "claude",
"adresse" : "rue des Poilus",
"localite": "62100 Calais",
"email": "allemandclaude@gmail.com",
"loisirs": ["Sport", "Cinema", "Lecture" , "Voyage"]
}
Notez que le contenu d'un fichier JSON est une séquence de type 'dictionnaire' (paires de clé-valeur).
Ouvrons le fichier "fiche.json" en mode commande.
>>> import json
>>> import os
>>> os.chdir("c:/python_prog")
>>> with open("fiche.json") as fichier:
... contenu = json.load(fichier)
...
>>> print(contenu)
{'nom': 'Allemand', 'prenom': 'claude', 'adresse': 'rue des Poilus', 'localite': '62100 Calais',
'email': 'allemandclaude@gmail.com', 'loisirs': ['Sport', 'Cinema', 'Lecture', 'Voyage']}
>>>
>>> for item in contenu.items():
... print(item)
...
('nom', 'Allemand')
('prenom', 'claude')
('adresse', 'rue des Poilus')
('localite', '62100 Calais')
('email', 'allemandclaude@gmail.com')
('loisirs', ['Sport', 'Cinema', 'Lecture', 'Voyage'])
>>>fichier.close()
Il faut importer le module json qui permet de manipuler des fichiers de ce format.
Pour récupérer le contenu du fichier, il faut utiliser la méthode load de ce module.
L'objet "contenu" est itérable (peut être parcouru avec une boucle).
Voyons maintenant comment créer un fichier JSON.
>>> personne = {'nom': 'Albert',
... 'email': 'albert99@gmail.com',
... 'loisirs': ['Sport', 'Cinema', 'Lecture', 'Voyage']
... }
>>> with open('fiche.json', 'w') as fichier:
... json.dump(personne, fichier)
>>>fichier.close()
Le fichier JSON "fiche.json" est créé à partir d'un dictionnaire.
Pour écrire dans un fichier JSON il faut utiliser la méthode dump du module json.
Le contenu précédent de "fiche.json" a été écrasé et remplacé par :
{"nom": "Albert", "email": "albert99@gmail.com", "loisirs": ["Sport", "Cinema", "Lecture", "Voyage"]}
Dans la pratique les fichiers CSV / JSON peuvent être très volumineux.
Avant de les analyser il faut les "nettoyer" : corriger les erreurs et omissions.
En effet ces énormes fichiers découlent souvent d'encodage manuels sur de longues périodes. Il y a forcément des erreurs de saisie.
La librairie pandas est parfaitement adaptée pour "nettoyer" puis analyser de grosses masses de données et ainsi faire
des prédictions ...
Pandas est une bibliothèque de Python spécialisée dans la manipulation et l'analyse des données, offrant des
structures comme les "dataframes" et les "séries" pour un traitement efficace de données structurées.
Des données pertinentes sont essentielles en science des données.
La science des données est une branche de l'informatique qui étudie comment stocker, utiliser et analyser d'énormes masses
de données afin d'en extraire des informations.
Attention Pandas est une bibliothèque ; il faut donc au préalable l'installer via l'utilitaire PIP.
Une série pandas est comparable à une colonne d'un tableau. Il s'agit donc d'un tableau unidimensionnel.
Je crée une série à partir d'une simple liste.
>>>import pandas as pd >>> a = [5, 7, 9] >>> maserie =pd.Series(a) >>> print(maserie) 0 5 1 7 2 9 dtype: int64 >>>print(maserie[0]) 5
J'ai utilisé la fonction Serie() de pandas pour créer une série nommée "maserie".
Sauf indication contraire, les valeurs sont identifiées par leur numéro d'index.
La première valeur a l'indice 0, la deuxième l'indice 1, etc.
print(maserie) : cet indice permet d'accéder à une valeur spécifique de la série.
>>> # pandas ayant été importé >>> maliste = [9,7,5] >>> maserie = pd.Series(maliste,index=["L1","L2","L3"]) >>> print(maserie) L1 9 L2 7 L3 5 dtype: int64 >>> print(maserie["L2"]) 7
L'argument index de la fonction Series() vous permet de nommer vos des "étiquettes" (index personnalisés).
>>> calories = {"jour1": 420, "jour2": 380, "jour3": 390}
>>> maserie = pd.Series(calories)
>>> print(maserie)
jour1 420
jour2 380
jour3 390
dtype: int64
Les clés du dictionnaire deviennent les index de la série.
Dans Pandas, les jeux de données sont généralement des tableaux multidimensionnels appelés dataframes.
# pandas ayant été installé et importé
>>> mondict = {'cars': ["BMW", "Volvo", "Ford"],'passagers': [3, 7, 2]}
>>> df = pd.DataFrame(mondict)
>>> print(df)
cars passagers
0 BMW 3
1 Volvo 7
2 Ford 2
Je viens de créer un dataframe nommé "df" en utilisant la fonction DataFrame() de la librairie Pandas. Notez les index créés par défaut : 0,1,2,...
>>>print(df.loc[0]) cars BMW passings 3 Name: 0, dtype: object
L'argument index de la fonction DataFrame() vous permet de personnaliser les index.
>>> # pandas ayant été installé et importé
>>> data = {"calories": [420, 380, 390],"durée": [50, 40, 45]}
>>> df = pd.DataFrame(data, index = ["lundi", "mardi", "mercredi"])
>>> print(df)
calories durée
lundi 420 50
mardi 380 40
mercredi 390 45
>>> print(df.loc["mardi"])
calories 380
duration 40
Name: day2, dtype: int64
Ci-dessus je personnalise les index puis j'accède à la ligne 2 du dataframe nommé "df" avec la clé 'mardi'.
Ces fichiers peuvent contenir des masses très importante de données.
Une analyse humaine d'une telle masse de données n'est pas envisageable.
Dans le cadre d'un traitement automatisé il faut d'abord créer un dataframe à partir du fichier.
On peut exporter au format CSV les données d'un tableur (excel, calc) vers un fichier CSV.
Il faut ensuite faire appel à Pandas pour créer un dataframe.
Ce fichier est stocké dans le dossier "c:/prog_python" (comme les scripts).
Durée,Pouls,Pouls_max,Calories 60,110,130,409.1 60,117,145,479.0 60,103,135,340.0 45,109,175,282.4 45,117,148,406.0 60,102,127,300.5 60,110,136,374.0 45,104,134,253.3 30,109,133,195.1 60,98,124,269.0 60,103,147,329.3 60,100,120,250.7 60,106,128,345.3 60,104,132,379.3 ... 60,105,140,290.8 60,110,145,300.4 60,115,145,310.2 75,120,150,320.4 75,125,150,330.4
Les données sont séparées par des virgules.
La présentation est tabulaire.
La première ligne contient les en-têtes.
Les durées sont exprimées en minutes.
Le tableau de données contient 168 lignes de données auquel il faut rajouter une ligne d'en-tête.
# dataframe_csv.py
# créer un dataframe à partir d'un fichier CSV
import pandas as pd
df = pd.read_csv('data2.csv')
print(df)
Utilisation de la fonction read_csv() de pandas pour créer un dataframe à partir du fichier CSV.
Duree Pouls Pouls_max Calories
0 60 110 130 409.1
1 60 117 145 479.0
2 60 103 135 340.0
3 45 109 175 282.4
4 45 117 148 406.0
.. ... ... ... ...
164 60 105 140 290.8
165 60 110 145 300.4
166 60 115 145 310.2
167 75 120 150 320.4
168 75 125 150 330.4
[169 rows x 4 columns]
Si vous avez un Dataframe volumineux l'instruction print(nomDataframe) renverra par défaut
que les 5 premières lignes, et les 5 dernières lignes.
Utilisez la fonction to_string() pour afficher l’intégralité du DataFrame.
Remplacez l'instruction print(df) par print(df.to_string())
Cette fois la totalité du dataframe est affichée.
Une grande masse de données peut aussi être stockée dans un fichier au format JSON.
Le format JSON n'est plus réservé pour un traitement via JS ; la bibliothèque Pandas, peut manipuler
ce type de fichier.
Il se nomme "data1.json".
Il reprend les mêmes données que data2.csv mais avec une structure json.
{
"Durée":{
"0":60,
"1":60,
"2":60,
"3":45,
"4":45,
"5":60,
...
"168":75
},
"Pouls":{
"0":110,
"1":117,
"2":103,
"3":109,
"4":117,
"5":102,
...
"168":125
},
"Pouls_max":{
"0":130,
"1":145,
"2":135,
"3":175,
"4":148,
"5":127,
...
"168":150
},
"Calories":{
"0":409.1,
"1":479.0,
"2":340.0,
"3":282.4,
"4":406.0,
"5":300.5,
...
"168":330.4
}
}
Ici il y a quatre objets JSON (identifiés : Durée, Pouls, Pouls_max & Calories) et chaque objet contient 168 paires de clé:valeur.
Chaque objet JSON a en fait une structure identique à un dictionnaire Python.
Cependant dans un objet JSON, les clés sont obligatoirement entre guillemets doubles.
# dataframe_json.py
# créer un dataframe à partir d'un fichier JSON
import pandas as pd
df = pd.read_json('data1.json')
print(df.to_string())
Emploi de la fonction read_json() de pandas pour produire un dataframe à partir d'un fichier JSON.
Affichage d'un dataframe avec 168 lignes.
Durée Pouls Pouls_max Calories
0 60 110 130 409.1
1 60 117 145 479.0
2 60 103 135 340.0
3 45 109 175 282.4
4 45 117 148 406.0
5 60 102 127 300.5
...
164 60 105 140 290.8
165 60 110 145 300.4
166 60 115 145 310.2
167 75 120 150 320.4
168 75 125 150 330.4
On obtient et c'est heureux, le même dataframe qu'à partir du fichier CSV.
Un dataframe obtenu à partir d'un fichier CSV ou JSON peut contenir des milliers de lignes ...
Afficher seulement des les 20 premières lignes ?
...
print(df.head(20))
print("-----------------")
print(df.info())
...
Emploi de la méthode head() appliquée à l'objet 'dataframe' argumentée avec le nombre de lignes à afficher puis de la méthode info().
Durée Pouls Pouls_max Calories 0 60 110 130 409.1 1 60 117 145 479.0 2 60 103 135 340.0 3 45 109 175 282.4 4 45 117 148 406.0 ... 17 45 90 112 NaN 18 60 103 123 323.0 19 45 97 125 243.0 ----------------- class 'pandas.DataFrame' RangeIndex: 169 entries, 0 to 168 Data columns (total 4 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 Durée 169 non-null int64 1 Pouls 169 non-null int64 2 Pouls_max 169 non-null int64 3 Calories 164 non-null float64 dtypes: float64(1), int64(3) memory usage: 5.4 KB None
Affichage de 20 premières lignes y compris la ligne d'en-têtes.
Si le nombre de lignes n’est pas spécifié, la méthode head() renvoit les 5 premières lignes.
La méthode info() indique entre autres le nombre de valeurs non nulles présentes dans chaque colonne.
Ici il y a 164 valeurs non nulles sur 169 dans la colonne "Calories".
Donc il ya 5 lignes sans aucune valeur pour cette colonne ...
Les cellules vides peuvent être problématiques lors de l'analyse des données.
Le nettoyage des données consiste à corriger dans le dataframe les données erronnées provenant
du fichier source.
Pour gérer quelques cellules vides, vous pouvez supprimer les lignes qui les contiennent.
Cette solution est généralement acceptable pour un ensemble de données très volumineux ;
la suppression de quelques lignes n'aura pas d'impact significatif sur le résultat.
# dataframe_csv_clean.py
# créer un dataframe à partir d'un fichier .csv
# puis dupliquer ce dataframe pour obtnir une version nettoyée
import pandas as pd
df = pd.read_csv('data3.csv')
print(df.to_string())
new_df = df.dropna()
print("------------------------")
print(new_df.to_string())
Cette fois nous créons un dataframe à partir d'un fichier de taille modeste ("data3.csv") ; il ne comprend que
31 lignes de données.
Ainsi vous serez capable d'appréhender d'un seul regard les données omises ou erronnées.
Ce programme crée deux dataframes à partir du fichier "data3.csv".
Par défaut, la méthode dropna() renvoie un nouveau DataFrame nettoyé et ne modifie pas l’original.
C'est la copie fidèle du fichier "data3.csv".
Durée Date Pouls Pouls_max Calories
0 60 '2020/12/01' 110 130 409.1
1 60 '2020/12/02' 117 145 479.0
2 60 '2020/12/03' 103 135 340.0
3 45 '2020/12/04' 109 175 282.4
4 45 '2020/12/05' 117 148 406.0
5 60 '2020/12/06' 102 127 300.0
6 60 '2020/12/07' 110 136 374.0
7 450 '2020/12/08' 104 134 253.3
8 30 '2020/12/09' 109 133 195.1
9 60 '2020/12/10' 98 124 269.0
10 60 '2020/12/11' 103 147 329.3
11 60 '2020/12/12' 100 120 250.7
12 60 '2020/12/12' 100 120 250.7
13 60 '2020/12/13' 106 128 345.3
14 60 '2020/12/14' 104 132 379.3
15 60 '2020/12/15' 98 123 275.0
16 60 '2020/12/16' 98 120 215.2
17 60 '2020/12/17' 100 120 300.0
18 45 '2020/12/18' 90 112 NaN
19 60 '2020/12/19' 103 123 323.0
20 45 '2020/12/20' 97 125 243.0
21 60 '2020/12/21' 108 131 364.2
22 45 NaN 100 119 282.0
23 60 '2020/12/23' 130 101 300.0
24 45 '2020/12/24' 105 132 246.0
25 60 '2020/12/25' 102 126 334.5
26 60 20201226 100 120 250.0
27 60 '2020/12/27' 92 118 241.0
28 60 '2020/12/28' 103 132 NaN
29 60 '2020/12/29' 100 132 280.0
30 60 '2020/12/30' 102 129 380.3
31 60 '2020/12/31' 92 115 243.0
Durée Date Pouls Pouls_max Calories 0 60 '2020/12/01' 110 130 409.1 1 60 '2020/12/02' 117 145 479.0 2 60 '2020/12/03' 103 135 340.0 3 45 '2020/12/04' 109 175 282.4 4 45 '2020/12/05' 117 148 406.0 5 60 '2020/12/06' 102 127 300.0 6 60 '2020/12/07' 110 136 374.0 7 450 '2020/12/08' 104 134 253.3 8 30 '2020/12/09' 109 133 195.1 9 60 '2020/12/10' 98 124 269.0 10 60 '2020/12/11' 103 147 329.3 11 60 '2020/12/12' 100 120 250.7 12 60 '2020/12/12' 100 120 250.7 13 60 '2020/12/13' 106 128 345.3 14 60 '2020/12/14' 104 132 379.3 15 60 '2020/12/15' 98 123 275.0 16 60 '2020/12/16' 98 120 215.2 17 60 '2020/12/17' 100 120 300.0 19 60 '2020/12/19' 103 123 323.0 20 45 '2020/12/20' 97 125 243.0 21 60 '2020/12/21' 108 131 364.2 23 60 '2020/12/23' 130 101 300.0 24 45 '2020/12/24' 105 132 246.0 25 60 '2020/12/25' 102 126 334.5 26 60 20201226 100 120 250.0 27 60 '2020/12/27' 92 118 241.0 29 60 '2020/12/29' 100 132 280.0 30 60 '2020/12/30' 102 129 380.3 31 60 '2020/12/31' 92 115 243.0
Ici les lignes 18, 22, 28 (lignes ayant des cellules vides) ont disparu !
Mais toutes les erreurs n'ont pas disparu. On a toujours :
# dataframe_csv_clean.py
# créer sur place un dataframe nettoyé
import pandas as pd
df = pd.read_csv('data3.csv')
df.dropna(inplace = True)
print(df.to_string())
La fonction dropna(inplace = True) ne renvoit pas deux dataframes ; la version nettoyée écrase la première version.
Une autre façon de gérer les cellules vides consiste à insérer une valeur.
df = pd.read_csv('data3.csv')
df.fillna(130, inplace = True)
print(df.to_string())
La méthode fillna() permet de remplacer les cellules vides (de n'importe quelle colonne) par une valeur, ici 130.
Le résultat n'est pas très heureux puisque une cellule "Date" de la ligne 26 contient désormais 130 ...
#dataframe_csv_clean2.py
import pandas as pd
df = pd.read_csv('data3.csv')
print(df.to_string())
print("---------------")
calories_moy = df["Calories"].mean()
# écrire dans les cellules 'calorie' vides
df = df.fillna({"Calories": calories_moy},inplace=True )
# remplacer une valeur dans une cellule 'Durée'
df.loc[7, 'Durée'] = 45
#supprimer ligne en doublon
df.drop_duplicates(inplace = True)
# convertir au format date
df['Date'] = pd.to_datetime(df['Date'], format='mixed')
# supprimer la ligne avec une date nulle
df.dropna(subset=['Date'], inplace = True)
#afficher un dataframe entièrement corrigé
print(df.to_string())
Ce programme vise à obtenir un dataframe débarassé de toutes les erreurs et omissions : cellules vides, données aberrantes, format incorrect, lignes en double.
La première partie du rendu affiche le dataframe brut mais aussi affiche la moyenne pour la colonne "Calories".
...
---------------
moyenne de la colonne 'Calories' : 304.68
Durée Date Pouls Pouls_max Calories
0 60 2020-12-01 110 130 409.10
1 60 2020-12-02 117 145 479.00
2 60 2020-12-03 103 135 340.00
3 45 2020-12-04 109 175 282.40
4 45 2020-12-05 117 148 406.00
5 60 2020-12-06 102 127 300.00
6 60 2020-12-07 110 136 374.00
7 45 2020-12-08 104 134 253.30
8 30 2020-12-09 109 133 195.10
9 60 2020-12-10 98 124 269.00
10 60 2020-12-11 103 147 329.30
11 60 2020-12-12 100 120 250.70
13 60 2020-12-13 106 128 345.30
14 60 2020-12-14 104 132 379.30
15 60 2020-12-15 98 123 275.00
16 60 2020-12-16 98 120 215.20
17 60 2020-12-17 100 120 300.00
18 45 2020-12-18 90 112 304.68
19 60 2020-12-19 103 123 323.00
20 45 2020-12-20 97 125 243.00
21 60 2020-12-21 108 131 364.20
23 60 2020-12-23 130 101 300.00
24 45 2020-12-24 105 132 246.00
25 60 2020-12-25 102 126 334.50
26 60 2020-12-26 100 120 250.00
27 60 2020-12-27 92 118 241.00
28 60 2020-12-28 103 132 304.68
29 60 2020-12-29 100 132 280.00
30 60 2020-12-30 102 129 380.30
31 60 2020-12-31 92 115 243.00
On obtient enfin donc un dataframe propre : corrigé de toutes les erreurs et avec seulement une ligne supprimée.
Maintenant on peut procéder à l'analyse automatique de ce dataframe et toujours avec la librairie Pandas.
Je crée un dataframe à partir du fichier "data2.csv" qui je le rappelle contient 168 lignes de données.
>>> import pandas as pd
>>> import os
>>> os.chdir("c:/python_prog")
>>> df = pd.read_csv('data2.csv')
>>> print(df.to_string())
Durée Pouls Pouls_max Calories
0 60 110 130 409.1
1 60 117 145 479.0
2 60 103 135 340.0
3 45 109 175 282.4
4 45 117 148 406.0
5 60 102 127 300.5
...
164 60 105 140 290.8
165 60 110 145 300.4
166 60 115 145 310.2
167 75 120 150 320.4
168 75 125 150 330.4
>>> print(df.corr())
Durée Pouls Pouls_max Calories
Durée 1.000000 -0.155408 0.009403 0.922721
Pouls -0.155408 1.000000 0.786535 0.025120
Pouls_max 0.009403 0.786535 1.000000 0.203814
Calories 0.922721 0.025120 0.203814 1.000000
La méthode corr() ignore les colonnes non numériques.
Le résultat de la méthode corr() est un tableau contenant de nombreux nombres qui représentent la force de la corrélation entre
deux colonnes.
Ces nombres varient de -1 à 1.
1 indique une corrélation parfaite (1 à 1) : pour cet ensemble de données, chaque augmentation d'une valeur dans la première colonne
entraîne une augmentation de l'autre.
0,9 indique également une bonne corrélation : si vous augmentez une valeur, l'autre augmentera probablement aussi.
-0,9 indique une corrélation tout aussi forte que 0,9, mais si vous augmentez une valeur, l'autre diminuera d'autant.
0,2 indique une très faible corrélation.
On constate que les variables "Durée" et "Durée" présentent une corrélation de 1,000000.
Ce qui est logique : chaque colonne est toujours parfaitement corrélée à elle-même.
Les variables "Durée" et "Calories" présentent une corrélation de 0,922721, ce qui est très bonne corrélation positive.
On peut donc prédire que plus l’entraînement est long, plus on brûle de calories.
Et inversement : si l’on brûle beaucoup de calories, l’entraînement a été plus long.
Les variables "Durée" et "Pouls_max" (fréquence cardiaque maxi) présentent une corrélation de 0,009403,
ce qui est très faible. Cela signifie qu’on ne peut pas prédire la fréquence cardiaque maximale à partir de la seule durée
de l’entraînement et vice-versa.
J'ai emploi le terme "prédiction" ; on aborde alors le "machine learning", qui est une composante de l'IA ...
Pour résumer mon propos je vous présente un exemple complet.
Dans le programme ci-dessous je produis un dataframe à partir du fichier "data3.csv" (31 lignes seulement).
Je crée une version nettoyée de ce dataframe et je calcule les corrélations les différentes colonnes.
#dataframe_csv_complet.py
import pandas as pd
df = pd.read_csv('data3.csv')
calories_moy = df["Calories"].mean()
print("moyenne de la colonne 'Calories' : " , calories_moy)
print("--------------------")
# écrire dans les cellules 'calories' vides
df = df.fillna({"Calories": calories_moy},inplace=True )
# remplacer une valeur dans une cellule 'Durée'
df.loc[7, 'Durée'] = 45
#supprimer ligne en doublon
df.drop_duplicates(inplace = True)
# convertir au format date
df['Date'] = pd.to_datetime(df['Date'],format='mixed')
# supprimer la ligne avec une date nulle
df.dropna(subset=['Date'], inplace = True)
#afficher un dataframe entièrement corrigé
print("dataframe nettoyé:")
print(df.to_string())
print("-----------------")
print("corrélations :" )
print(df.corr())
-----------------
corrélations :
Durée Date Pouls Pouls_max Calories
Durée 1.000000 0.212084 -0.083417 -0.296585 0.338213
Date 0.212084 1.000000 -0.369328 -0.517827 -0.358014
Pouls -0.083417 -0.369328 1.000000 0.261426 0.478723
Pouls_max -0.296585 -0.517827 0.261426 1.000000 0.329600
Calories 0.338213 -0.358014 0.478723 0.329600 1.000000
La masse de données n'est peut-être pas suffisante pour en tirer des prédictions ...
Téléchargez le fichier compressé contenant les fichiers CSV & JSON
Comme l'illustre l'article de presse ci-dessus on utilise beaucoup les fréquences cumulées en économie et démographies.
Une fréquence est exprimée pour 1 ou pour 100, donc toujours par rapport à l'effectif total.
La bibliothèque Pandas est parfaitement adaptée pour traiter statistiquement des tableaux de données ('dataframes')
pour produire entre autres des fréquences et fréquences cumulées.
Ci-dessous : notes obtenues par une classe à une épreuve.
Les notes sont comprises entre 1 et 5.
Concevez le programme qui calcule les effectifs, effectifs cumulés, fréquences et fréquences cumulées.
# FRC.py
# effectif simple et cumulés
import statistics as stat
import pandas as pd
import matplotlib.pyplot as plt
# liste des notes d'une classe (note entre 1 et 5)
notes = [5,4,3,4,1,3,2,3,4,1,5,4,3,2,1,1,2,3,4,5]
#utilisation du module statistics
moyenne = stat.mean(notes)
mode = stat.multimode(notes)
mediane =stat.median(notes)
print("Note moyenne : ", moyenne)
print("Note(s) modale(s) : ", mode)
print("Note médiane : ", mediane)
print("-----------------")
# création d'une série pandas à partir de la liste des notes
notes =pd.Series(notes)
# calcul des effectifs simples et cumulés
effectif = notes.value_counts().sort_index()
print("affichage de la série 'effectif' ")
print(effectif)
print("--------------------")
effectif_cum = effectif.cumsum()
print("affichage de la série 'effectif_cum'")
print(effectif_cum)
# calcul des fréquences simples et cumulées.
frequence = effectif / effectif.sum()
frequence_cum = frequence.cumsum()
# Tableau des effectifs et fréquences
print("tableau des effectifs et fréquences")
df = pd.DataFrame({
'Effectif' : effectif,
'Effectif cumulé' : effectif_cum,
'Effectif en % ' : frequence *100,
'Effectif cumulé en %': frequence_cum *100
})
print(df)
# graphique
largeur = 1
plt.bar(df.index,frequence_cum *100, largeur)
plt.title("Fréquences cumulées")
plt.xlabel("Notes")
plt.ylabel("fréquences cumulées en %")
plt.show()
Notez les importations. J'ai besoin du module statistics pour calculer les valeurs centrales. J'ai besoin de matplotlib.pyplot pour représenter le diagramme des fréquences cumulées.
Remarque : une série statistique discrète peut avoir plusieurs modes.
C'est le cas ici : pour la note 3 et pour la note 4 l'effectif est maximum : 5 copies.
Il faut donc mieux utiliser la fonction statistics.multimode() Cette fonction retourne une liste.
effectif = notes.value_counts().sort_index() : que fait cette instruction ?
La méthode value_counts() compte les occurrences pour chaque valeur dans la série "notes".
la méthode sort_index() trie la nouvelle série par valeur.
Les valeurs sont les index de cette nouvelle série nommée "effectif".
Ce qui donne pour l'exemple :
1 4en 2 3 3 5 4 5 5 3
effectif_cum = effectif.cumsum() :
la méthode cum_sum() appliquée à la série "effectif" produit une nouvelle série nommée "effectif_cum" avec
les cumuls.
frequence = effectif / effectif.sum() : utilisation de la fonction sum() pour obtenir la série des fréquences nommée "frequence". Ce qui donne : 4/20 , 3/20, 5/20 ... Donc ici les fréquences sont exprimées pour 1 !
Il y a ensuite construction d'un dataframe nommé "df" à partir des différentes séries produites (effectif, effectif_cum, frequence, frequence_cum).
L'histogramme des fréquences cumulées est bâti à partir des index du dataframe "df" et de la colonne "frequences_cum".
Note moyenne : 3 Note(s) modale(s) : [4, 3] Note médiane : 3.0 ----------------- affichage de la série 'effectif' 1 4 2 3 3 5 4 5 5 3 -------------------- affichage de la série 'effectif_cum' 1 4 2 7 3 12 4 17 5 20 -------------------------- Tableau des effectifs et fréquences Effectif Effectif cumulé Effectif en % Effectif cumulé en % 1 4 4 20.0 20.0 2 3 7 15.0 35.0 3 5 12 25.0 60.0 4 5 17 25.0 85.0 5 3 20 15.0 100.0 --------------------
Analyse du tableau :
60% des élèves ont 3 ou moins
85% des élèves ont 4 ou moins
Donc 25% des élèves ont la note 4
etc.
Revoyez la partie sur le module matplotlib.pyplot dans le chapitre 14.
Mathématiques et statistiques en Python
Dans beaucoup de pays la notation est basée sur des lettres.
La liste des notes à analyser :
notes = ['A','B','C','B','E','C','D','D','B','E','A','B','C','D','C','E','D','C','B','A','E']
Je vous communique ci-dessous le rendu du programme.
À vous de reconstituer ce script .
nombre de notes : 21 Note(s) modale(s) : ['B', 'C'] notes triées : ['A', 'A', 'A', 'B', 'B', 'B', 'B', 'B', 'C', 'C', 'C', 'C', / 'C', 'D', 'D', 'D', 'D', 'E', 'E', 'E', 'E'] médiane : C affichage de la série 'effectif' A 3 B 5 C 5 D 4 E 4 -------------------- affichage de la série 'effectif_cum' A 3 B 8 C 13 D 17 E 21 --------------- tableau des effectifs et fréquences Effectif Effectif cumulé Effectif en % Effectif cumulé en % A 3 3 14.285714 14.285714 B 5 8 23.809524 38.095238 C 5 13 23.809524 61.904762 D 4 17 19.047619 80.952381 E 4 21 19.047619 100.000000 ----------------------------
On ne peut pas calculer la moyenne d'une série de lettres.
La fonction stat.multimode() fonctionne même avec une série de lettres.
Par contre la fonction stat.median() 'plante'. Pour déterminer la médiane, l'astuce consiste à
trier les notes par valeurs croissantes et extraire la note de rang 11 (puisque la série comprend 21 notes).
En complément de Pandas on peut aussi utiliser les nombreuses fonctions de la bibliothèque Numpy.
Revoyez éventuellement la partie sur la librairie Numpy dans le chapitre 14.
Mathématiques et statistiques en Python
Numpy est très à l'aise pour calculer les centiles (déciles, quartiles) fort utilisées pour étudier les inégalités
dans une population.