ProPython
Pandas - La référence pour la manipulation de données
07 Apr, 2021

Pandas - La référence pour la manipulation de données

Pandas est une librairie très connue pour l'analyse et la manipulation de données en Python. Elle est notamment très utilisée en data science. Son nom est une référence à la fois à "Panel Data" et "Python Data Analysis".

Pandas va nous permettre par exemple d'analyser de grandes quantités de données et d'en déduire des statistiques, ou alors de rendre plus lisibles des grands ensembles de données, ce qui est très important en data science.

Pandas vous permet de modéliser simplement des données d'apparence complexe, par exemple pour modéliser des données boursières avec le prix d'ouverture, de fermeture, la date d'ouverture, etc... Elle vous permet également de calculer des corrélations entre données, ou bien de calculer une moyenne, un maximum, un minimum...

Démarrer avec Pandas

Mise en place

Installation

La première chose à faire afin d'utiliser Pandas, c'est de l'installer. Pour cela on utilise pip comme pour toute autre installation de librairie. Ouvrez votre interface en ligne de commande (cmd.exe) et exécutez la commande suivante :

pip install pandas

Importation

Il faut maintenant importer la librairie. Ouvrez votre interpréteur Python et importez la de la façon suivante :

import pandas

Note : Pandas est souvent importée avec l'alias pd en Python, de cette façon, par convention, je vous conseille de faire pareil :

import pandas as pd

De nouveaux types de données

Les Series

Une Serie est un tableau d'une dimension pouvant contenir n'importe quel type de données. C'est comme une colonne ou une ligne. Voici comment créer une Serie, par exemple à partir d'une liste :

>>> my_list = ['a', 'b', 'c']
>>> my_serie = pd.Series(my_list)
>>> my_serie
0    a
1    b
2    c
dtype: object

Lorsque l'on affiche une Serie, la première colonne affichée est la colonne correspondant aux index, et la seconde correspond aux valeurs de notre Serie. Le type est également affiché (dtype). Mais maintenant, que peut-on faire avec notre Serie ?

On peut afficher ses valeurs. Par défaut, si aucun index n'est spécifié, l'index de chaque valeur est son numéro. On accède donc aux valeurs d'une série en utilisant les index, ici ce sera donc de cette façon :

>>> my_serie[0]
'a'
>>> my_serie[2]
'c'

On peut également modifier l'index par défaut lors de l'initialisation d'une Serie.

>>> my_serie = pd.Series(my_list, index=['x', 'y', 'z'])
>>> my_serie
x    a
y    b
z    c
dtype: object

On passe simplement en second paramètre notre liste d'index, qui doit donc être de même taille que celle de la liste de nos valeurs. Maintenant, pour accéder à une valeur de la Serie, on utilise son index comme au dessus, sauf que cette fois les index ont changé.

>>> my_serie['x']
'a'
>>> my_serie['y']
'b'

Note : on peut toujours accéder aux valeurs d'une série dont les index ont changé en utilisant les numéros comme plus haut, par exemple, my_serie[0] ne génèrera pas d'erreur, même en ayant changé les index.

On peut également initialiser une série en utilisant un dictionnaire. Dans ce cas, le clés seront les index, et les valeurs seront les valeurs de la série.

>>> my_dict = {'x': 'a', 'y': 'b', 'z': 'c'}
>>> my_serie = pd.Series(my_dict)
>>> my_serie
x    a
y    b
z    c
dtype: object

On peut également spécifier le paramètre index pour n'utiliser que les valeurs dont on aura précisé l'index.

>>> my_serie = pd.Series(my_dict, index=['x', 'z'])
>>> my_serie
x    a
z    c
dtype: object

C'est tout pour les séries. Pour l'instant, vous trouvez peut-être qu'elles ressemblent à des listes un peu particulières, et c'est le cas, mais nous verrons plus tard en quoi elles sont utiles.

Les DataFrames

Un DataFrame est un peu comme un assemblage de plusieurs Series. C'est un tableau multi-dimensionnel. On peut créer un DataFrame de plusieurs façons. L'une d'elles est d'utiliser un dictionnaire dont les clés sont les noms des colonnes, et les valeurs sont des listes correspondant aux valeurs des colonnes. Voici un exemple pour comprendre :

>>> data = {"names": ["Jean", "Yves", "Paul"], "ages": [41, 45, 32]}
>>> df = pd.DataFrame(data)
>>> df
  names  ages
0  Jean    41
1  Yves    45
2  Paul    32

On peut également initialiser un DataFrame en utilisant une liste de listes. Dans ce cas chaque sous-liste correspondra à une rangée du DataFrame.

>>> data = [["Jean", 41], ["Yves", "45"], ["Paul", 32]]
>>> df = pd.DataFrame(data)
>>> df
      0   1
0  Jean  41
1  Yves  45
2  Paul  32

Remarquez que dans cet exemple, les colonnes n'ont pas de noms et sont donc nommées avec l'index par défaut. Pour leur donner un nom, on utlise l'argument columns lors de l'initialisation du DataFrame, et on passe en paramètre une liste correspondant aux index des colonnes.

>>> df = pd.DataFrame(data, columns=["names", "ages"])
>>> df
  names ages
0  Jean   41
1  Yves   45
2  Paul   32

Pour accéder aux données contenues dans un DataFrame, il y a plusieurs moyens. D'abord, on peut utiliser la méthode loc[index] (mettez bien des crochets et non des parenthèses). Cette méthode nous renvoie une Serie dont les index sont les colonnes du DataFrame, et les valeurs sont les valeurs de ces colonnes, à la ligne dont l'index est passé en paramètres. Un exemple en reprenant le DataFrame ci-dessus :

>>> df.loc[0]
names    Jean
ages       41
Name: 0, dtype: object

On récupère la ligne d'index 0 sous forme de Serie. On peut également récupérer plusieurs lignes en même temps. Dans ce cas, au lieu de récupérer une Serie on récupère un DataFrame.

>>> df.loc[[0, 1]]
  names ages
0  Jean   41
1  Yves   45

De la même façon que pour les Serie, on peut modifier les index des lignes d'un DataFrame. On utilise l'argument index à l'initialisation.

>>> df = pd.DataFrame(data, columns=["names", "ages"], index=['a', 'b', 'c'])
>>> df
  names ages
a  Jean   41
b  Yves   45
c  Paul   32

Et pour accéder aux index nommés, on utilise simplement loc(index) comme précédemment.

>>> df.loc['b']
names    Yves
ages       45
Name: b, dtype: object

Finalement, une autre façon d'initialiser un DataFrame est d'utiliser un fichier csv. Pour cela, on utilise la fonction pd.read_csv(chemin)chemin est le chemin pour accéder au fichier qu'on souhaite ouvrir. Si votre fichier est situé dans le même répertoire que votre script, le chemin sera alors simplement son nom. Si vous le souhaitez, vous pouvez télécharger le fichier data.csv mis à votre disposition afin d'essayer la méthode read_csv.

Si jamais vous avez téléchargé le fichier, mettez le n'importe où, à la racine de C:/ par exemple, et ouvrez le avec Pandas :

>>> df = pd.read_csv("C:/data.csv")
>>> df
     Duration  Pulse  Maxpulse  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.0
166        60    115       145     310.2
167        75    120       150     320.4
168        75    125       150     330.4

[169 rows x 4 columns]

Notre DataFrame est trop long, donc tout n'est pas affiché. Seules les 5 premières et les 5 dernières colonnes sont affichées. Si l'on souhaite modifier ce comportement, on peut modifier la variable suivante : pd.options.display.max_rows qui définit le nombre maximal de lignes à afficher.

pd.options.display.max_rows = 9999

Ici, on affichera au maximum 9999 lignes, ce qui est largement suffisant je pense.

On peut également utiliser la fonction pd.read_json(chemin) afin de convertir les données d'un fichier JSON en DataFrame. Si vos données JSON sont sous forme de dictionnaire, vous savez déjà comment créer un DataFrame à partir d'un dictionnaire.

Manipuler des données

Analyser des données

Vous savez maintenant comment créer des Series et des DataFrames. La prochaine étape est donc de les utiliser afin de manipuler correctement des données.

En data science, une fois qu'on a collecté nos données, il est important de les comprendre et de les analyser. C'est ce que nous allons voir, grossièrement. Pour les exemples, on va considérer le DataFrame étudié à la fin de la section précédente, chargé à partir d'un fichier csv.

D'abord, on aimerait obtenir une vue rapide des éléments de ce DataFrame. On utilise pour cela la méthode head(lignes) de notre DataFrame en lui passant en paramètre le nombre de lignes qu'on souhaite visualiser.

>>> df.head(10)
   Duration  Pulse  Maxpulse  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.0
6        60    110       136     374.0
7        45    104       134     253.3
8        30    109       133     195.1
9        60     98       124     269.0

Ici, on affiche les 10 dernières lignes de notre DataFrame. Pour afficher les 10 dernières lignes, on utilise la méthode tail qui s'utilise de la même façon.

>>> df.tail(10)
     Duration  Pulse  Maxpulse  Calories
159        30     80       120     240.9
160        30     85       120     250.4
161        45     90       130     260.4
162        45     95       130     270.0
163        45    100       140     280.9
164        60    105       140     290.8
165        60    110       145     300.0
166        60    115       145     310.2
167        75    120       150     320.4
168        75    125       150     330.4

Maintenant, on aimerait obtenir quelques informations sur notre DataFrame. On utilise la méthode info.

>>> df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 169 entries, 0 to 168
Data columns (total 4 columns):
 #   Column    Non-Null Count  Dtype
---  ------    --------------  -----
 0   Duration  169 non-null    int64
 1   Pulse     169 non-null    int64
 2   Maxpulse  169 non-null    int64
 3   Calories  164 non-null    float64
dtypes: float64(1), int64(3)
memory usage: 5.4 KB

Cela nous indique que notre DataFrame contient 169 lignes, ordonnées de 0 à 168, et qu'il contient 4 colonnes, avec leur nom, leur index, le nombre de valeurs non nulles, et le type de valeur stockée pour chaque colonne. Finalement, on obtient également l'emplacement pris en mémoire par notre DataFrame. Remarquez que pour la colonne "Calories", le nombre de valeurs non nulles est de 164, et non 169. Cela signifie que 5 valeurs sont nulles.

Si on veut des informations plutôt statistiques sur notre DataFrame, on dispose de méthodes pour calculer la moyenne, la médiane, ou pour trouver la valeur apparaissant le plus souvent par exemple.

>>> df.mean()  # Moyenne
Duration     68.4375
Pulse       103.5000
Maxpulse    128.5000
Calories    304.6800
dtype: float64
>>> df.median()  # Médiane
Duration     60.0
Pulse       102.5
Maxpulse    127.5
Calories    291.2
dtype: float64
>>> df.mode()  # Valeurs les plus fréquentes
   Duration          Date  Pulse  Maxpulse  Calories
0        60  '2020/12/12'    100       120     300.0

Si l'on souhaite utiliser ces méthodes, mais sur une colonne uniquement du DataFrame, ont peut récupérer la colonne de cette façon :

>>> df["Calories"]
...
>>> df["Calories"].mean()
304.68

Nettoyer des données

Nous avons vu précédemment qu'un DataFrame pouvait contenir des valeurs nulles. Ces valeurs sont des valeurs qu'on souhaite éviter et qu'on pourrait définir comme de la mauvaise donnée. Un autre exemple de mauvaise donnée serait des valeurs au mauvais format. Il est donc important de bien nettoyer les données avec lesquelles on souhaite travailler avant toute chose. Nous allons utiliser pour la suite un DataFrame contenant quelques imperfections, vous pouvez le télécharger ici : dirtydata.csv

>>> df = pd.read_csv("C:/dirtydata.csv")
>>> df
    Duration          Date  Pulse  Maxpulse  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
>>> df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 32 entries, 0 to 31
Data columns (total 5 columns):
 #   Column    Non-Null Count  Dtype
---  ------    --------------  -----
 0   Duration  32 non-null     int64
 1   Date      31 non-null     object
 2   Pulse     32 non-null     int64
 3   Maxpulse  32 non-null     int64
 4   Calories  30 non-null     float64
dtypes: float64(1), int64(3), object(1)
memory usage: 1.4+ KB

Ce DataFrame contient des mauvaises données (valeurs nulles, lignes dupliquées, valeurs mal formatées, valeur étranges), nous allons voir comment le traiter.

Supprimer les valeurs nulles

Pour commencer, nous allons nous débarrasser des lignes contenant des valeurs nulles. Pour cela, on utilise la méthode dropna qui fait tout le boulot.

>>> df = df.dropna()
>>> df.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 29 entries, 0 to 31
Data columns (total 5 columns):
 #   Column    Non-Null Count  Dtype
---  ------    --------------  -----
 0   Duration  29 non-null     int64
 1   Date      29 non-null     object
 2   Pulse     29 non-null     int64
 3   Maxpulse  29 non-null     int64
 4   Calories  29 non-null     float64
dtypes: float64(1), int64(3), object(1)
memory usage: 1.4+ KB

On constate que toutes nos colonnes contiennent maintenant le même nombre de valeurs non nulles. Remarquez qu'on déclare un nouveau DataFrame. En effet, df.dropna() ne modifie pas le DataFrame sur lequel on travaille, mais en renvoie simplement une version modifiée. On peut modifier ce comportement en ajoutant l'argument inplace=True, qui permet de préciser qu'on souhaite modifier le DataFrame sur lequel on travaille et non en renvoyer une copie modifiée.

>>> df.dropna(inplace=True)
# Identique à df = df.dropna()

On aurait également pu faire autrement, par exemple en remplaçant les valeurs nulles par une autre valeur plutôt que de les supprimer. En effet, si notre DataFrame est petit et contient beaucoup de valeurs nulles, supprimer les rangées les contenant rend le DataFrame encore plus petit, et donc pas forcément représentatif de ce qu'on modélise. Pour remplacer les valeurs nulles, on utilise la méthode fillna(valeur).

>>> df.fillna(100, inplace=True)
# Remplace les valeurs nulles par 100

On peut également préciser les colonnes sur lesquelles on veut effectuer ces actions, si jamais on ne veut pas effectuer la même chose partout.

>>> df["Calories"].fillna(100, inplace = True)

Formatter correctement les données

Si vous regardez notre DataFrame, vous remarquez qu'à la ligne 26, pour la colonne "Date", nous n'avons pas une date mais un nombre. On aimerait convertir ce nombre en date.

On utilise pour cela la fonction pd.to_datetime(data) qui convertit des données en date.

>>> df['Date'] = pd.to_datetime(df['Date'])

Se débarrasser des mauvaises données

Quelque fois, des mauvaises données peuvent être simplement des données qui ne sont pas représentatives, ou bien des données qui ont mal été rentrées. Par exemple, quelqu'un peut très bien avoir écrit à l'ordinateur 300 au lieu de 3.00. Et cela fausse tout, il faut donc se débarrasser de ces données. Dans notre DataFrame, à la ligne 7, la valeur de la colonne "Duration" est 450, ce qui est trop élevé par rapport aux autres lignes. On doit donc se débarrasser de cette valeur. Vous vous souvenez comment on sélectionne une ligne dans un DataFrame ? On utilise la méthode loc. Ici, on va préciser en plus un second paramètre qui correspond à la colonne à laquelle on souhaite accéder.

>>> df.loc[7, "Duration"]  # On accède à la ligne 7 de la colonne "Duration"
450
>>> df.loc[7, "Duration"] = 45

Mais on ne peut pas faire cela à la main pour toutes les valeurs si jamais notre DataFrame est trop grand. On doit donc le parcourir, et éliminer ces valeurs éventuellement. Pour cela, on peut utiliser une boucle :

>>> for index in df.index:
...     if df.loc[index, "Duration"] > 110:
...             df.loc[index, "Duration"] = 110
# Met à 110 toutes les valeurs supérieures à 110

On aurait pu également supprimer les rangées où les valeurs sont incorrectes, plutôt que de les modifier, pour cela on utilise la méthode drop(index) qui supprime une rangée en fonction de l'index :

>>> for index in df.index:
...   if df.loc[index, "Duration"] > 120:
...     df.drop(index, inplace = True)

Supprimer les doublons

La dernière étape est de supprimer les lignes en doubles qui auraient pu être insérées par erreur par exemple. La méthode duplicated nous renvoie une Serie contenant en index les index de notre DataFrame, et en valeurs un booléen égal à True si la ligne est un doublon, False sinon.

>>> df.duplicated()
0     False
1     False
2     False
3     False
4     False
5     False
6     False
7     False
8     False
9     False
10    False
11    False
12     True
13    False
14    False
15    False
16    False
17    False
19    False
20    False
21    False
23    False
24    False
25    False
26    False
27    False
29    False
30    False
31    False
dtype: bool

Une méthode existe pour supprimer les doublons :

>>> df.drop_duplicates(inplace = True)

Le mot de la fin

Voilà, vous en connaissez maintenant un petit peu plus sur la librairie Pandas. On peut faire beaucoup d'autres choses, le but de l'article n'est pas de présenter une liste exhaustive des fonctionnalités, pour cela vous avez la documentation, mais au moins vous savez dans les grandes lignes comment fonctionne cette librairie qu'il est PRIMORDIAL de connaitre en Python.

Si cet article vous a plus, n'hésitez pas à laisser un commentaire ! Si vous avez des questions, que vous avez besoin de précisions ou que vous avez des retours à me faire, vous pouvez également me contacter via l'onglet disponible sur le site !

Laisser un commentaire

Premium - 15€/mois

L'accès à des articles inédits, à une multitude de ressources, à de nouveaux projets, mais également à des vidéos explicatives, découvrez ici pourquoi passer premium.

Articles liés

Catégories

Ressources

Retrouvez une collection de ressources (des scripts, des fiches résumé, des images...) liées aux articles du blog ou au Python.
Voir

Contact

contact@propython.fr
Se connecter pour envoyer un message directement depuis le site.

Navigation

AccueilSe connecterCréer un compteRessourcesPremium

Catégories

Pages légales

Politique de confidentialitéMentions légalesConditions générales de vente