• 10 heures
  • Moyenne

Ce cours est visible gratuitement en ligne.

course.header.alt.is_video

course.header.alt.is_certifying

J'ai tout compris !

Mis à jour le 28/03/2019

Passez de Numpy à Pandas

Connectez-vous ou inscrivez-vous gratuitement pour bénéficier de toutes les fonctionnalités de ce cours !

Avec  Numpy  et  Matplotlib  , la librairie  Pandas  fait partie des librairies de base pour la data science en Python. Pandas fournit des structures de données puissantes et simples à utiliser, ainsi que les moyens d'opérer rapidement des opérations sur ces structures. Dans ce chapitre, nous verrons l'intérêt de la librairie Pandas, ainsi que les opérations basiques sur l'objet phare de cette librairie, le dataframe.

Mais commençons par un peu de réflexion !

Réfléchissons un peu

Imaginons que nous souhaitions représenter des animaux. Disons... des pandas par exemple !

Nous pouvons caractériser un panda par sa taille ; ou plutôt, par ses tailles : disons par exemple, la taille de ses pattes, la longueur moyenne des poils de sa fourrure, la taille de sa queue, et le diamètre de son ventre.

On peut représenter ce pandas par un tableau numpy :

import numpy as np
un_panda_numpy = np.array([100,5,20,80])
un_panda_numpy
array([100,  5, 20, 80])

Ici, notre panda a des pattes de 100cm, des poils de 5cm en moyenne, une queue de 20cm et un ventre de 80cm de diamètre.

Et si je veux représenter plusieurs pandas, je crée une liste de np.array?

C'est une bonne idée. Il est effectivement possible de faire cela :

famille_panda = [
    np.array([100, 5  , 20, 80]), # maman panda
    np.array([50 , 2.5, 10, 40]), # bébé panda
    np.array([110, 6  , 22, 80]), # papa panda
]

Mais comme nous l'avons vu précédemment, nous pouvons faire mieux car notre liste de 3 pandas, c'est en fait un tableau multidimensionnel, que NumPy gère très bien !

famille_panda = [
    [100, 5  , 20, 80], # maman panda
    [50 , 2.5, 10, 40], # bébé panda
    [110, 6  , 22, 80], # papa panda
]
famille_panda_numpy = np.array(famille_panda)
famille_panda_numpy
array([[ 100. , 5. , 20. , 80. ],
       [  50. , 2.5, 10. , 40. ],
       [ 110. , 6. , 22. , 80. ]])

Quel avantage?

Par exemple, supposons que je veuille obtenir la taille des pattes (situé en position 0 dans chaque liste qui décrit un panda) du panda situé en position 2 dans ma liste (c'est-à-dire papa panda). Numpy offre la possibilité de le faire élégamment :

famille_panda_numpy[2, 0] # taille des pattes de papa panda, à la manière numpy
110.0

Et si je veux connaître les tailles des pattes de toute ma famille panda ?

Facile ! Il suffit de supprimer le 2 (qui correspondait au papa panda), et de le remplacer par le caractère:, signifiant que je veux TOUS les pandas !

famille_panda_numpy[:, 0]
array([ 100., 50., 110.])

Voilà ! La taille des pattes de la maman est de 100cm, celle du bébé 50cm, et celle du papa 110cm.

C'est assez pratique certes, mais écrire   famille_panda_numpy[:, 0]  quand on veut connaître la taille des pattes des pandas, ce n'est pas très explicite. j'aimerais pouvoir spécifier quelque-part que ce  0  correspond à la taille des pattes !

Cela nous amène à la librairie Pandas !

La librairie Pandas

Tout est une histoire de tableau !

Au fait, la manière dont j'ai écrit la variablefamille_panda:

famille_panda = [
    [100, 5  , 20, 80],
    [50 , 2.5, 10, 40],
    [110, 6  , 22, 80],
]

... ça ressemble un peu à un tableau avec des lignes et des colonnes non ? Vous ne trouvez pas que c'est très similaire à cela?

 

pattes

poil

queue

ventre

maman_panda

100

5

20

80

bébé_panda

50

2.5

10

40

papa_panda

110

6

22

80

(La bonne réponse est : "Oui, c'est très similaire")

Dans ce cas, pourquoi ne pas utiliser une librairie Python qui manipulerait des tableaux comme celui-ci ? Cette librairie existe, et elle s'appelle Pandas.

C'est parti, représentons nos pandas avec Pandas !

import pandas as pd
famille_panda_df = pd.DataFrame(famille_panda)
famille_panda_df
    0    1    2    3
0   100  5.0  20  80
1   50   2.5  10  40
2   110  6.0  22  80

L'objet qui permet de représenter des "tableaux" est l'objet DataFrame. Pour instancier un tel objet (et pour lui donner de la donnée), on lui transmet une liste de rang 2, c'est à dire une liste de listes.

Nous pouvons même faire mieux, en indiquant les noms de colonnes et les noms des lignes. Et encore mieux : la librairie Pandas se base en grande partie sur la librairie Numpy dans son fonctionnement interne. Comme pandas connaît intimement Numpy, on peut très bien transmettre à l'objet DataFrame de la donnée au format ndarray :

famille_panda_df = pd.DataFrame(famille_panda_numpy,
                                index = ['maman', 'bebe', 'papa'],
                                columns = ['pattes', 'poil', 'queue', 'ventre'])
famille_panda_df
        pattes  poil  queue  ventre
 maman   100.0   5.0   20.0    80.0
 bebe     50.0   2.5   10.0    40.0
 papa    110.0   6.0   22.0    80.0

Vous allez encore me demander quel est l'intérêt de cette librairie n'est-ce pas ?

En fait, l'objet DataFrame est très similaire à certains concepts que l'on trouve en dehors du cadre du langage Python. Il est similaire :

  • aux tables des bases de données relationnelles (type MySQL, PostgreSQL, etc.) que l'on manipule grâce au langage SQL

  • à l'objet dataframe sur lequel se base tout le langage R, langage destiné aux statisticiens et aux Data Analysts

Du coup, si vous connaissez déjà le langage SQL ou le langage R, vous aurez beaucoup de facilité à utiliser le DataFrame de Pandas !

Quelques fonctionnalités des DataFrames

Voici quelques petites fonctionnalités des Dataframes.

Tout d'abord, accédons à la colonne ventre de notre table. Il y a deux syntaxes possibles, qui renvoient exactement le même résultat :

famille_panda_df.ventre
famille_panda_df["ventre"]
maman     80.0
bebe      40.0
papa      80.0
Name: ventre, dtype: float64

 Parcourrons maintenant tous les pandas un à un, grâce à la méthode iterrows qui renvoie (à chaque itération de la boucle for) un tuple dont le premier élément est l'index de la ligne, et le second le contenu de la ligne en question :

for ind_ligne, contenu_ligne in famille_panda_df.iterrows():
    print("Voici le panda %s :" % ind_ligne)
    print(contenu_ligne)
    print("--------------------")

 Voici le panda maman :
 pattes     100.0
 poil         5.0
 queue       20.0
 ventre      80.0
 Name: maman, dtype: float64
 --------------------
 Voici le panda bebe :
 pattes     50.0
 poil        2.5
 queue      10.0
 ventre     40.0
 Name: bebe, dtype: float64
 --------------------
 Voici le panda papa :
 pattes    110.0
 poil        6.0
 queue      22.0
 ventre     80.0
 Name: papa, dtype: float64
 --------------------

Accédons maintenant au papa panda : d'abord par sa position (position 2), puis par son nom "papa". Le résultat retourné est exactement le même dans les 2 cas.

famille_panda_df.iloc[2] # Avec iloc(), indexation positionnelle
famille_panda_df.loc["papa"] # Avec loc(), indexation par label
pattes   110.0
poil       6.0
queue     22.0
ventre    80.0
Name: papa, dtype: float64

Déterminons les pandas dont le diamètre du ventre est de 80cm :

famille_panda_df["ventre"] == 80
maman    True
bebe    False
papa     True
Name: ventre, dtype: bool

Le résultat de cette opération est très pratique pour filtrer des lignes ! Par exemple, pour sélectionner uniquement les pandas dont le ventre est de 80cm, il suffit d'intégrer ce précédent résultat en tant que masque, comme ceci :

masque = famille_panda_df["ventre"] == 80
pandas_80 = famille_panda_df[masque]

# On écrit plus souvent cela de cette manière :
# pandas_80 = famille_panda_df[famille_panda_df["ventre"] == 80]

pandas_80
       pattes  poil  queue  ventre
maman   100.0   5.0   20.0    80.0
papa    110.0   6.0   22.0    80.0

Qu'est-ce qu'un masque ?

Lorsque vous mettez un masque sur votre visage, celui-ci cache certaines parties de votre tête, mais en laisse visible d'autres : vos yeux, votre nez et votre bouche. Ici, c'est un peu la même chose : comme nous souhaitons ne garder que certaines lignes du dataframe, et en cacher d'autres, nous appliquons un masque. Un masque est ici une liste de variables booléennes (TrueouFalse) dans laquelle chaque élément est associé à une ligne du dataframe. Si cet élément estTrue, cela signfie que nous souhaitons garder la ligne en question. Si nous souhaitons ne pas garder la ligne, cet élément estFalse.

Pour inverser le masque, il suffit d'utiliser l'opérateur~, et nous sélectionnons les pandas qui n'ont pas un ventre de 80cm :

famille_panda_df[~masque]
      pattes  poil  queue  ventre
bebe    50.0   2.5   10.0    40.0

Maintenant, ajoutons des lignes à notre dataframe. Il y a plusieurs méthodes pour cela, mais voyons ici la plus simple : assemblons ensemble deux dataframes.

quelques_pandas = pd.DataFrame([[105,4,19,80],[100,5,20,80]],      # deux nouveaux pandas
                               columns = famille_panda_df.columns) 
                               # même colonnes que famille_panda_df
tous_les_pandas = famille_panda_df.append(quelques_pandas)
tous_les_pandas
        pattes  poil queue ventre
 maman   100.0   5.0  20.0   80.0
 bebe     50.0   2.5  10.0   40.0
 papa    110.0   6.0  22.0   80.0
 0       105.0   4.0  19.0   80.0
 1       100.0   5.0  20.0   80.0

Dans le dataframe tous_les_pandas, il y a des doublons. En effet, le premier panda (maman) et le dernier panda (dont l'index est 1) ont exactement les mêmes mesures. Si nous souhaitions dédoublonner, nous ferions ceci :

tous_les_pandas.drop_duplicates()
        pattes  poil  queue  ventre
 maman   100.0   5.0   20.0    80.0
 bebe     50.0   2.5   10.0    40.0
 papa    110.0   6.0   22.0    80.0
 0       105.0   4.0   19.0    80.0
 1       100.0   5.0   20.0    80.0

 Allez, encore un petit effort ! Voici quelques autres fonctionnalités en vrac, que nous utiliserons dans le projet :

# accéder aux noms des colonnes
famille_panda_df.columns

# créer une nouvelle colonne, composée de chaînes de caractères
famille_panda_df["sexe"] = ["f", "f", "m"] 
# la maman et le bébé sont des femelles, le papa est un mâle

# obtenir le nombre de lignes
len(famille_panda_df)
# obtenir les valeurs distinctes d'une colonne :
# pour la colonne ventre, il y a deux valeurs distinctes : 40 et 80
famille_panda_df.ventre.unique()
array([ 80.,  40.])

Lire un fichier CSV avec Pandas

Un fichier CSV (comma separated values), c'est un fichier permettant de représenter des données sous forme de tableau. D'ailleurs, si vous utilisez un logiciel de type tableur, il y a fort à parier qu'il puisse lire et exporter au format CSV !

Vous me voyez venir ? La librairie Pandas est justement spécialisée dans la manipulation de tableaux ! Lire un fichier CSV avec Pandas est donc un jeu d'enfant : il ne suffit que d'une ligne pour créer un dataframe à partir d'un CSV :

data = pd.read_csv("data.csv", sep=";")

C'est fait ! La variabledata contient maintenant un dataframe contenant les données du fichier csv. Petite particularité ici : dans notre fichier CSV, les valeurs sont séparées par le caractère;. Par défaut, pd.read_csv attend des valeurs séparées par une virgule. Nous sommes donc obligés de spécifier sep=";". Pour en savoir plus sur  read_csv , faites un petit tour sur la doc ;) ! Pour avoir un exemple d'utilisation, visitez le haut de ce chapitre.

Exemple de certificat de réussite
Exemple de certificat de réussite