ProPython
Datascience avec Python - Pandas Part. 1
25 Jun, 2021

Datascience avec Python - Pandas Part. 1

Dans cet article, nous allons voir quelques fonctionnalités de Pandas utiles pour la datascience. Avant de commencer, il est conseillé d'avoir lu cet article : Pandas - La référence pour la manipulation de données, mais ce n'est pas obligatoire car je vais repasser rapidement sur les principaux concepts de Pandas.

Pour commencer, nous allons installer Pandas. Pour cela, comme d'habitude, on utilise pip :

pip install pandas

On peut maintenant importer ce framework de cette façon, qui est la façon la plus commune dans la communauté Python utilisant Pandas :

import pandas as pd

Series

Une Serie est un tableau étiqueté unidimensionnel capable de contenir des données de n'importe quel type (entier, chaîne, flottant, objets python, etc.). Une Serie dans Pandas renvoie à la fois les valeurs et les index qui associés.

Voici comment créer votre première Serie :

>>> serie = pd.Series([10, 20, 34, 23, 19, 20])
>>> serie
0    10
1    20
2    34
3    23
4    19
5    20
dtype: int64

On passe une liste en paramètre du constructeur. Ensuite, en affichant notre Serie, on obtient la liste des valeurs, les index associés, et le dtype, c'est à dire le type des valeurs contenues dans la Serie. Pour une Serie contenant des objets de types différents, le dtype deviendra object.

Ensuite, on peut récupérer les indexs de notre Serie de cette façon :

>>> serie.axes
[RangeIndex(start=0, stop=7, step=1)]

On constate qu'ici l'index est un RangeIndex, qui est un objet de Pandas décrivant un index à la manière de la fonction range, avec une valeur de départ, une valeur de fin, et un pas.

On peut également récupérer le dtype dont je vous parlais précédemment :

>>> serie.dtype
dtype('int64')

Puis la taille de la Serie :

>>> serie.size
6
>>> len(serie)
6

Et aussi le nombre de dimensions de la Serie (qui est 1 par définition, mais qui peut être différent pour les DataFrames que nous verrons après).

>>> serie.ndim
1

On peut récupérer les valeurs de la Serie sous forme d'array Python :

>>> serie.values
array([10, 20, 34, 23, 19, 20], dtype=int64)

On peut aussi spécifier les index lors de la création d'une Serie :

>>> serie = pd.Series([10, 20, 34, 23, 19, 20], index=['a', 'b', 'c', 'd', 'e', 'f'])
>>> serie
a    10
b    20
c    34
d    23
e    19
f    20
dtype: int64
>>> serie.index
Index(['a', 'b', 'c', 'd', 'e', 'f'], dtype='object')

Bien sûr, il faut que l'index que vous passez en paramètre soit de même taille que votre Serie, sinon cela génèrera une erreur.

On peut également trier la Serie selon son index :

>>> serie = pd.Series([9, 10, 20, 34, 23, 19, 20], index=['z', 'a', 'b', 'c', 'd', 'e', 'f'])
>>> serie.sort_index()
a    10
b    20
c    34
d    23
e    19
f    20
z     9
dtype: int64

Ici, comme j'utilise des caractères en guise d'index, la Serie est triée dans l'ordre alphabétique. Si j'avais utilisé des nombres, elle serait triée par ordre croissant des nombres.

On peut aussi utiliser des dictionnaires pour créer des Series, dans ce cas la clé deviendra l'index, et la valeur la valeur associée à cet index :

>>> scores = {'John': 10, 'Scarlett': 9, 'Johan': 23}
>>> serie = pd.Series(scores)
>>> serie
John        10
Scarlett     9
Johan       23
dtype: int64

On peut également ne conserver que certaines valeurs en précisant l'index :

>>> serie = pd.Series(scores, index=['Scarlett', 'Johan'])
>>> serie
Scarlett     9
Johan       23
dtype: int64

On peut aussi créer des Series à partir de tableaux Numpy :

>>> values = np.array([12, 3, 54, 45, 56])
>>> serie = pd.Series(values)
>>> serie
0    12
1     3
2    54
3    45
4    56
dtype: int32

Une dernière façon de créer des Series, est en fusionnant deux Series existantes :

>>> serie1 = pd.Series(range(3, 8))
>>> serie2 = pd.Series(range(34, 41))
>>> serie = pd.concat([serie1, serie2])
>>> serie
0     3
1     4
2     5
3     6
4     7
0    34
1    35
2    36
3    37
4    38
5    39
6    40
dtype: int64

La dernière chose à savoir est qu'on peut utiliser des sélecteurs à la manière de ce qu'on fait avec des listes :

>>> serie[0:2]
0    3
1    4
dtype: int64
>>> serie[-1:-4: -1]
6    40
5    39
4    38
dtype: int64

Voilà, vous savez une bonne partie de ce qu'il y a à savoir sur les Series ! On va maintenant pouvoir passer aux DataFrames.

DataFrames

Un DataFrame est une structure de données tabulaire hétérogène, bidimensionnelle et de taille variable, dont les axes (lignes et colonnes) sont étiquetés. Un DataFrame est une structure de données bidimensionnelle, c'est-à-dire que les données sont alignées de manière tabulaire en lignes et en colonnes.

Pour créer un DataFrame, on peut utiliser un dictionnaire :

>>> persons = {'Names': ['John', 'Scarlett', 'Johan'], 'Scores': [12, 10, 23]}
>>> dataframe = pd.DataFrame(persons)
>>> dataframe
      Names  Scores
0      John      12
1  Scarlett      10
2     Johan      23

Vous comprenez peut-être mieux pourquoi je parlais d'une structure de données tabulaire.

En fait, chaque colonne correspond à une Serie. On peut les récupérer de cette façon :

>>> names = dataframe['Names']
>>> names
0        John
1    Scarlett
2       Johan
Name: Names, dtype: object
>>> type(names)
<class 'pandas.core.series.Series'>

Ou de cette façon :

>>> df.Names
0        John
1    Scarlett
2       Johan
Name: Names, dtype: object

Maintenant, plutôt que de créer un DataFrame en utilisant un dictionnaire, on peut utiliser une liste de listes :

>>> values1 = [1, 2]
>>> values2 = [10, 11]
>>> df = pd.DataFrame([values1, values2], columns=['a', 'b'])
>>> df
    a   b
0   1   2
1  10  11

De la même manière que pour créer des Series, on peut créer des DataFrames en utilisant des tableaux Numpy.

>>> arr1 = np.array([1, 2])
>>> arr2 = np.array([10, 11])
>>> df = pd.DataFrame([arr1, arr2])
>>> df
    0   1
0   1   2
1  10  11
>>> df[0]
0     1
1    10
Name: 0, dtype: int32

On obtient la même chose qu'avant. Notez que lorsqu'on ne précise pas de noms pour les colonnes, des noms par défaut sont générés.

On peut récupérer les index de la même façon que pour les Series :

>>> df.axes
[RangeIndex(start=0, stop=2, step=1), RangeIndex(start=0, stop=2, step=1)]

On peut également récupérer la "shape" du DataFrame, qui correspond au nombre de lignes et au nombre de colonnes du DataFrame :

>>> df.shape
(2, 2)

Puis on peut récupérer son nombre de dimensions, qui correspond au nombre de colonnes (vous comprenez maintenant pourquoi ce nombre est forcément égal à 1 pour une Serie) :

>>> df.ndim
2

On peut récupérer sa taille :

>>> df.size
4
>>> len(df)
2

La taille du DataFrame est le nombre de valeurs qu'il contient. Sa longueur (qu'on récupère avec len est le nombre de lignes).

On peut récupérer ses colonnes et son index :

>>> df.columns
RangeIndex(start=0, stop=2, step=1)
>>> df.index
RangeIndex(start=0, stop=2, step=1)

Ici, les colonnes et l'index sont pareils, créons rapidement un autre DataFrame pour bien différencier ceci :

>>> persons = {'Names': ['John', 'Scarlett', 'Johan'], 'Scores': [12, 10, 23]}
>>> df = pd.DataFrame(persons)
>>> df.columns
Index(['Names', 'Scores'], dtype='object')
>>> df.index
RangeIndex(start=0, stop=3, step=1)

On peut également récupérer les valeurs du DataFrame sous forme de array :

>>> df.values
array([['John', 12],
       ['Scarlett', 10],
       ['Johan', 23]], dtype=object)

On peut récupérer une ligne de DataFrame sous forme de Serie :

>>> first_row = df.iloc[0]
>>> first_row
Names     John
Scores      12
Name: 0, dtype: object

Si on veut changer les valeurs d'une ligne :

>>> new_row = ['Bob', 45]
>>> df.iloc[1] = new_row
>>> df
   Names  Scores
0   John      12
1    Bob      45
2  Johan      23

Evidemment, il faut que la nouvelle ligne contienne autant de valeurs que le nombre de colonnes.

On peut ajouter un nouvel index :

>>> df.set_index('Names')
       Scores
Names
John       12
Bob        45
Johan      23
>>> df
   Names  Scores
0   John      12
1    Bob      45
2  Johan      23

Comme vous le remarquez, le DataFrame original n'est pas modifié, mais set_index renvoie un nouveau DataFrame. Pour modifier le DataFrame original, il faut utiliser l'argument inplace=True :

>>> df.set_index('Names', inplace=True)
>>> df
       Scores
Names
John       12
Bob        45
Johan      23

Cette fois-ci, set_index ne renvoie rien et le DataFrame original est modifié. Plus globalement, pour de nombreuses opérations Pandas sur les DataFrames, le mot-clé inplace permet de préciser si on souhaite modifier le DataFrame original ou non.

On peut également mettre plusieurs index à un DataFrame :

>>> df.set_index(['Names', 'Scores'], inplace=True)
>>> df
Empty DataFrame
Columns: []
Index: [(John, 12), (Scarlett, 10), (Johan, 23)]

Le DataFrame est maintenant vide puisque toutes les colonnes qu'il possédait sont devenues des index. On va donc ajouter une colonne à notre DataFrame :

>>> df['Numbers'] = [1, 2, 3]
>>> df
                 Numbers
Names    Scores
John     12            1
Scarlett 10            2
Johan    23            3

L'affichage est maintenant correct.

On peut accéder à une ligne précise en fonction de son index :

>>> df.loc['John']
        Numbers
Scores
12            1

Comme pour les Series, on peut trier les DataFrames en fonction des index :

>>> df.sort_index(inplace=True)
>>> df
                 Numbers
Names    Scores
Johan    23            3
John     12            1
Scarlett 10            2

On peut filtrer les DataFrames :

>>> df['Numbers'] >= 2
Names     Scores
Johan     23         True
John      12        False
Scarlett  10         True
Name: Numbers, dtype: bool

Si on veut utiliser plusieurs conditions :

>>> df[(df['Numbers'] >= 2) & (df['Numbers'] == 2)]
                 Numbers
Names    Scores
Scarlett 10            2
>>> df[(df['Numbers'] >= 2) | (df['Numbers'] == 1)]
                 Numbers
Names    Scores
Johan    23            3
John     12            1
Scarlett 10            2

Si on veut l'opposé d'un filtre, on utilise le symbol tilde :

>>> df[~((df['Numbers'] >= 2) | (df['Numbers'] == 1))]
Empty DataFrame
Columns: [Numbers]
Index: []

On peut également utiliser concat comme pour les Series :

>>> df
                 Numbers
Names    Scores
Johan    23            3
John     12            1
Scarlett 10            2
>>> df2 = pd.DataFrame([4], columns=['Numbers'])
>>> new_df = pd.concat([df, df2])
>>> new_df
                Numbers
(Johan, 23)           3
(John, 12)            1
(Scarlett, 10)        2
0                     4

Remarquez que les index peuvent être de nature différente, cela ne pose pas de problème dans un DataFrame.

Finalement, on peut également supprimer des lignes d'un DataFrame, voici un exemple :

>>> df.drop(df[df['Numbers'] >= 3].index, inplace=True)
>>> df
                 Numbers
Names    Scores
John     12            1
Scarlett 10            2

Vous save maintenant pas mal de choses sur les DataFrales, nous verrons la suite dans un prochain article !

Le mot de la fin

Cet article était un peu spécial : il contient beaucoup de code et va directement à l'essentiel. Je pense que je vais plutôt m'orienter vers ce format car c'est le plus simple à lire, pour les choses qui ne demandent pas nécessairement d'expliquations en tous cas !

Si l'article vous a plu et que vous souhaitez faire un retour, ou alors si vous avez des questions, n'hésitez pas à me contacter ou à laisser un commentaire.

On se retrouve dans un prochain article pour la suite de votre apprentissage de la datascience avec Python.

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