ProPython
Datascience avec Python - Découverte de Numpy
08 May, 2021
Prérequis
Bases de Python

Datascience avec Python - Découverte de Numpy

NumPy est une librairie mathématique pour Python. Elle vous permet de réaliser beaucoup de choses sur de grandes quantités de données, de façon efficace et optimisée.

Dans cet article, je vais me contenter de vous présenter rapidement NumPy et ce qui est nécessaire pour la Datascience et le Machine Learning. Nous n'allons pas voir tout ce qu'il est possible de réaliser avec cette librairie, nous verrons cela plus en détail dans d'autres articles.

Les Bases

La toute première chose à faire est évidemment d'installer NumPy. Pour cela, on utilise simplement pip.

pip install numpy

Bien, maintenant on peut importer Numpy :

import numpy as np

Par convention, on importe toujours NumPy de cette façon.

Maintenant, nous allons découvrir l'objet principal de NumPy : un tableau multidimensionnel.

Créer des tableaux multidimensionnels

L'objet principal de NumPy est le tableau multidimensionnel homogène. C'est un tableau d'éléments (généralement des nombres), tous du même type, indexés par un tuple d'entiers non négatifs. Les dimensions sont appelées axes.

Par exemple, le tableau des coordonnées d'un point dans l'espace 3D, [1, 2, 1], a un axe. Cet axe contient 3 éléments, nous disons donc qu'il a une longueur de 3. Et voici à quoi ressemblerait un tableau à 2 axes par exemple : [[1, 2, 1], [2, 3, 5]].

Un tableau avec NumPy est matérialisé par l'objet np.array. Voici donc comment on peut créer le tableau de notre exemple :

a = np.array([[1, 2, 1], [2, 3, 5]])
print(a)
# [[1 2 1]
[2 3 5]]
OK, mais pourquoi utiliser un tableau NumPy plutôt qu'un tableau classique ?

Les tableaux classiques (array) ne sont pas vraiment optimisés en Python, et ne permettent de travailler qu'avec un axe. De plus, NumPy nous propose des fonctions et des méthodes pour nous simplifier la vie avec les np.array, donc autant en profiter !

np.arange()

Cette fonction permet de créer un tableau contenant les nombres d'une valeur de début à une valeur de fin, avec éventuellement un pas. Par exemple :

a = np.arange(1, 10, 2)
print(a)
# [1 3 5 7 9]

Le premier paramètre est la valeur à laquelle commencer (par défaut 0). Le second paramètre est la valeur de fin. Et la dernière est le pas (par défaut 1). Ici par exemple, on souhaite créer un tableau contenant les valeurs de 1 à 10 avec un pas de 2. Donc 1, 3, 5, 7, et 9. Attention, la valeur de fin n'est pas comprise dans le tableau. Par exemple, on pourrait se dire que np.arange(1, 11, 2) va prendre les valeurs de 1 à 11, sauf que la valeur de fin est exclue, donc on ne prendra que les valeurs de 1 à 9.

np.linspace()

Cette fonction nous permet aussi de créer un tableau contenant des valeurs comprises dans un intervalle. En revanche, le troisième paramètre n'est plus le pas, mais le nombre de valeurs que l'on souhaite obtenir. En fait, cette fonction divise notre intervalle en n valeurs, de telle sorte que l'espace entre chaque valeur soit le même, et met nos valeurs dans un tableau. Attention, cette fois la valeur de fin est comprise dans le tableau. Voici un exemple :

a = np.linspace(1, 10, 10)
print(a)
# [ 1.  2.  3.  4.  5.  6.  7.  8.  9. 10.]

On obtient 10 valeurs également réparties entre 1 et 10 (inclus), donc 1, 2, 3, ..., 10.

Forme d'un tableau

La forme est un attribut d'un np.array. Comme son nom l'indique, elle permet de connaître la forme d'un tableau. Pour bien comprendre la forme, on peut considérer les tableaux comme des matrices. Un tableau contenant 3 ensembles de 4 éléments pourra ainsi être associé à une matrice de 3 lignes et 4 colonnes. Par exemple :

a = np.array([[1, 2]])
b = np.array([[1, 9], [2,7], [4, 1]])
print(a.shape)
print(b.shape)
# (1, 2)
# (3, 2)

Notre premier tableau est une matrice de 1 ligne et 2 colonnes, sa forme est donc (1, 2). Notre second tableau est une matrice de 3 lignes et 2 colonnes, sa forme est donc (3, 2). Remarquez que pour initialiser notre premier tableau, j'ai utilisé les double crochets, même si le tableau ne contient qu'un axe. Cela permet de dire qu'on souhaite associer notre tableau à une matrice potentiellement multi-dimensionnelle. Si on ne met pas les double crochets, alors notre tableau sera forcément une matrice à une unique dimension.

np.array.reshape()

Imaginez que vous aillez une matrice de 10 colonnes et 10 lignes. Vous pouvez la réarranger de plusieurs façons, par exemple en la changeant en une matrice de 50 colonnes et 2 lignes, ou bien 25 lignes et 4 colonnes, etc... La méthode reshape vous permet d'effectuer ceci. Pour cela, il suffit de l'appliquer sur un tableau en lui passant en paramètre la nouvelle forme (sous forme de tuple contenant d'abord le nombre de lignes, ensuite le nombre de colonnes) et de récupérer le résultat. Bien sûr, il faut que la forme soit possible. Par exemple, on ne peut pas réarranger une matrice 3X3 en matrice 5X3, ou 2X4. Voici un exemple :

a = np.array([[1, 9], [2,7], [4, 1]])
b = a.reshape((1, 6))
print(a)
print(b)

# a
[[1 9]
 [2 7]
 [4 1]]

# b
[[1 9 2 7 4 1]]

c = a.reshape((2, 2))  # Impossible

Maintenant nous allons voir quelques fonctions de génération de matrices utilisant la forme.

np.zeros()

Cette fonction permet de créer une matrice remplie de zéros, dont la forme est passée paramètre.

a = np.zeros((3, 3))
print(a)

# a
[[0. 0. 0.]
 [0. 0. 0.]
 [0. 0. 0.]]

np.eye()

Cette fonction permet de générer une matrice identité dont la taille est passée en paramètres. Puisque c'est une matrice identité, c'est une matrice carrée donc il suffit de ne passer qu'une dimension en paramètre, de cette façon :

a = np.eye(3)
print(a)

# a
[[1. 0. 0.]
 [0. 1. 0.]
 [0. 0. 1.]]

Petit rappel mathématique : une matrice identité est une matrice contenant autant de lignes que de colonnes, remplie de 0 sauf pour la diagonale allant du coin supérieur gauche au coin inférieur droit, qui ne contient que des 1.

Manipuler des Matrices

A partir de maintenant je vais toujours utiliser le terme "matrice" pour désigner un np.array. C'était bien de dire "tableau" au début pour comprendre, mais "matrice" est quand même plus représentatif et plus explicite.

Nous allons voir comment manipuler des matrices. Pour l'instant, vous ne savez que changer leur forme. Vous allez voir comment effectuer des manipulations un peu plus avancées, comme des additions, multiplications, etc...

Addition/Soustraction

Pour réaliser ces opérations, on peut simplement utiliser les opérateurs arithmétiques + et -. Cependant, il faut toujours respecter les règles d'algèbre de base, c'est à dire que vous ne pouvez effectuer de telles opérations qu'avec des matrices de même forme.

a = np.eye(3)
b = np.arange(1, 10).reshape(3, 3)
m = a + b
print(m)

# m 
[[ 2.  2.  3.]
 [ 4.  6.  6.]
 [ 7.  8. 10.]]

On peut aussi effectuer des opérations entre matrices et scalaires. Par exemple, si je souhaite retirer 2 à toute une matrice, je le fais de cette façon :

a = np.eye(3)
b = a-2
print(b)

# b
[[-1. -2. -2.]
 [-2. -1. -2.]
 [-2. -2. -1.]]

Multiplication

Pour la multiplication, c'est un peu différent. On ne peut pas utiliser l'opérateur multiplication, sinon ce n'est pas une multiplication matricielle, mais une multiplication classique, appliquée entre deux matrices. Regardez :

a = np.eye(3)
b = np.arange(1, 10).reshape((3, 3))
m = a*b
print(m)

# m
[[1. 0. 0.]
 [0. 5. 0.]
 [0. 0. 9.]]

Pour ceux qui ont fait un peu de maths, vous remarquez que nous ne devons pas obtenir ce résultat, car multiplier une matrice par la matrice identité revient à obtenir la matrice d'origine. En fait, la multiplication a simplement multiplié chaque nombre de la matrice a par le nombre de la matrice b situé à la même position dans la matrice.

Pour obtenir un vrai produit matriciel, on utilise la méthode dot.

a = np.eye(3)
b = np.arange(1, 10).reshape((3, 3))
m = np.dot(a, b)
print(m)

# m
[[1. 2. 3.]
 [4. 5. 6.]
 [7. 8. 9.]]

Et voilà, on obtient le bon résultat !

Dernier mot sur la multiplication : de la même façon que pour l'addition et la soustraction, on peut utiliser l'opérateur multiplication avec un scalaire :

a = np.eye(3)
m = a*5
print(m)

# m
[[5. 0. 0.]
 [0. 5. 0.]
 [0. 0. 5.]]

A vous de voir en fonction de ce que vous souhaitez réaliser si vous devez utiliser une multiplication classique, ou une multiplication matricielle.

Somme totale d'une matrice

Pour finir, on va voir comment on peut obtenir la somme de tous les éléments d'une matrice, ou comment sommer selon les lignes ou les colonnes.

Pour faire la somme de toutes les valeurs d'une matrice, on utilise la fonction np.sum(). Elle ne prend qu'un seul paramètre : la matrice dont on souhaite connaître la somme.

a = np.eye(3)
m = a*5
total = np.sum(m)
print(total)

# 15.0

Pour sommer selon un axe, on le précise en paramètre. Dans le cas d'une matrice à deux dimensions, on précise soit 0 pour sommer selon les colonnes, sinon 1 pour sommer selon les lignes.

a = np.arange(1, 10).reshape((3, 3))
print(np.sum(a, axis=0))

# [12 15 18]

12 est la somme des valeurs de la première colonne, 15 de la deuxième, et 18 de la troisième.

Selon les lignes maintenant :

a = np.arange(1, 10).reshape((3, 3))
print(np.sum(a, axis=1))

# [ 6 15 24]

Matrices à plus de 2 dimensions

Evidemment, tout ce que vous pouvez faire avec des matrices à 2 dimensions, vous pouvez le faire avec des matrices à plus de dimensions. Cependant, les manipulations deviennent vite compliquées et moins intuitives, c'est pourquoi je ne vais pas trop en parler. Je vais juste vous parler rapidement de la forme d'une matrice.

Je vous ai dit que la forme est sous forme de tuple, et que ce tuple contient d'abord le nombre de lignes, ensuite le nombre de colonnes. Il faut oublier cette notion de lignes et de colonnes quand vous manipulez des matrices à plus de 2 dimensions, il vaut mieux penser en axes.

Ainsi, une forme est un tuple contenant les longueurs des axes. Par exemple, voici une forme à plus de deux dimensions : (3, 6, 2, 9). Un np.array ayant cette forme possèdera 4 axes : le premier de longueur 3, ensuite 6, 2, et 9.

Toutes les fonctions dont nous avons parlé sont utilisables avec des np.array à plus de deux dimensions, en revanche de tels tableaux ne sont pas très fréquemment utilisés, donc je ne vais pas rentrer dans le détail, à vous d'expérimenter.

Le mot de la fin

NumPy est très utilisée en Datascience, et il est essentiel de connaître au moins les quelques bases que vous avez lues dans cet article avant de passer à la suite. En effet, pour manipuler beaucoup de données, il est mieux d'utiliser NumPy que de chercher à utiliser des listes Python qui sont bien moins optimisées.

Si l'article vous a plus, que vous souhaitez faire un retour ou que vous avez des questions, n'hésitez pas à laisser un commentaire ! Vous pouvez aussi me contacter par mail ou via le site !

On se retrouve prochainement 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