
Comme vous l’avez peut-être vu au travers des différents articles de ce blog, Python est un langage puissant et flexible. La panoplie de librairies disponibles aident les développeurs a créé des applications webs mais également scientifiques. La librairie « NumPy » que je vais vous présenter est dédiée au calcul numérique pour les scientifiques ou tous ceux qui ont besoin de faire du calcul numérique.
NumPy est le raccourci pour Numerical Python. C’est une librairie open-source qui propose des outils très utiles pour le calcul scientifique. La vaste gamme d’outils vous donnera la possibilité de travailler sur des tableaux à plusieurs dimensions, plus communément appelés matrices.
Contrairement aux listes, les tableaux « array » doivent contenir des données de type homogène et numériques. Nous avons vu dans cet article que les listes peuvent accéder différents types ce qui n’est pas le cas pour les tableaux. Ils accepteront les données de type entier (« integer ») et réel (« float »).
Quel est le but de cette librairie ?
NumPy a été développé pour manipuler facilement et rapidement des tableaux de données numériques. Contrairement aux listes en Python, vous pourrez appliquer différentes opérations mathématiques sur les tableaux et ce de manière très efficace. Vous pourriez vous amuser à réaliser la même chose en travaillant sur les listes mais le résultat ne sera pas aussi efficace. De plus, vous n’avez qu’à tendre les bras pour utiliser cette librairie !!
Qu’est-ce qu »un tableau ?
NumPy n’utilise pas de peinture ! 🙂 Blague à part, vous pouvez imaginer un tableau comme une grille dans laquelle vous allez accéder aux différentes valeurs entre rentrant leur numéro de ligne et de colonne. C’est un peu comme à la bataille navale.
Comment installer la librairie NumPy ?
pip install numpy
PythonCette commande rentrée dans votre interpréteur permettra de télécharger et installer la dernière version de Numpy. Vous pouvez également télécharger le code source depuis le site de NumPy et l’installer vous-même.
Importer la librairie Numpy
import numpy as np
PythonVous noterez l’utiliser de l’instruction « as ». Lorsque vous importez une fonction ou un module, vous pouvez leur donner un autre nom qui sera plus simple d’utilisation dans le code. Dans notre cas, au lieu d’utiliser « numpy » à chaque fois que vous souhaitez accéder à la librairie, « np » suffira. Cette façon de faire est très répondu pour améliorer la lisibilité du code.
Création d’un tableau avec NumPy
Vous pouvez créer manuellement vos tableaux via la commande « array() » en lui donnant comme argument une liste de nombre. Si vous souhaitez créer un tableau à deux dimensions, il faudra alors lui donner les valeurs sous forme de listes imbriquées. La première liste correspond à la première ligne et ainsi de suite. NumPy permet de créer des tableaux de dimensions supérieures à 3. Le cerveau humain est limité à la troisième dimension. En effet nous vivons dans un espace à 3 dimensions. Cependant, numériquement, il n’y a aucun souci pour utiliser des tableaux à 5 ou 6 dimensions.
# Création d'un vecteur, tableau à 1 dimension
a = np.array([1, 2, 3])
# Création d'un tableau à 2 dimensions : deux lignes, trois colonnes
b = np.array([[1, 2, 3],[4, 5, 6]])
PythonPour accéder aux valeurs du tableau, comme pour les listes, vous aurez besoin du nom de la variable et de l’indice que vous souhaitez accéder.
a[1] # Deuxième élément du vecteur
>>> 2
b[1,2] # Deuxième ligne, troisième colonne
>>> 6
PythonPour simplifier l’initialisation de vecteur ou de matrices, il existe deux fonctions permettant de créer des vecteurs ou des matrices en les remplissant automatiquement avec des 0 ou des 1. Egalement, suivant vos besoins, les fonctions « eye » et « identify » vous permettront de créer une matrice avec des 1 sur la diagonale. La fonction « eye » vous permet de créer une matrice rectangulaire (N différent de M) tandis que la fonction « identity » vous renvoie forcément une matrice carrée.
a = np.zeros(3) # Création d'un vecteur à 3 composantes, composé de 0 uniqument
a
>>> array([0., 0., 0.])
np.ones((2, 3)) # Création d'une matrice à 2 lignes et 3 colonnes, composée de 1 uniqument
>>> array([[1., 1., 1.],
>>> [1., 1., 1.]])
np.eye(2,3)
>>> array([[1., 0., 0.],
>>> [0., 1., 0.]])
np.identity(2)
>>> array([[1., 0.],
>>> [0., 1.]])
PythonIl est possible de créer un vecteur avec une suite arithmétique via la fonction « arange ». La fonction « linspace » vous permet de créer un vecteur d’une valeur de départ jusqu’à une valeur de fin avec un nombre d’éléments défini.
numpy.arange([start, ]stop, [step,] dtype=None, *, like=None)
Comme pour la fonction « range » pour les boucles « for » (article sur le sujet ici), on peut déterminer soit le dernier élément exclus avec un pas de 1 par défaut, soit la valeur de départ et de fin exclue. Vous pouvez rajouter la valeur du pas dans cette dernière configuration.
numpy.linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None, axis=0)
Comme pour la fonction arange, vous devrez spécifier la valeur de départ, la valeur de fin et le nombre de valeurs que vous souhaitez. Par défaut, vous aurez 50 éléments. A la différence de « arange », la valeur de fin est inclue dans le résultat par défaut. L’argument « endpoint » permet de jouer sur cet effet.
np.arange(4) # Suite arithmétique avec un incrément par défaut de 1 de 0 jusqu'à 4 exclu
>>> array([0, 1, 2, 3])
np.arange(2, 9, 2) # Suite arithmétique avec un incrément de 2, de 2 jusqu'à 9 exclu
>>> array([2, 4, 6, 8])
np.linspace(0, 20, num=5)
>>> array([ 0., 5., 10., 15., 20.])
PythonSpécifier le type de données dans le tableau. Comme expliqué dans l’article sur les variables, bien spécifier le type permet de gagner en performance. Voici un exemple :
x = np.ones(2, dtype=np.int8) # Par défaut, les valeurs sont des réels (float) codés sur 64 bits
x
>>> array([1, 1], dtype=int8)
PythonInformations sur le tableau
Afin de pouvoir travailler sur un tableau, vous aurez certainement besoin de récupérer quelques informations à son sujet. Voici trois fonctions qui pourront vous servir à récupérer le nombre de dimensions, la taille totale et la taille de chaque dimension.
import numpy as np
mon_tableau = np.array([[[1, 2, 3],
[4, 5, 6],
[7, 8, 9]],
[[10, 20, 30,],
[40, 50, 60,],
[70, 80, 90,]],
[[15, 25, 35,],
[45, 55, 65,],
[75, 85, 95,]]]
mon_tableau.ndim
>>> 3
mon_tableau.size
>>> 27
mon_tableau.shape
>>> (3, 3, 3)
PythonManipulation les tableaux avec NumPy
Redimensionner et ajouter une dimension
Vous pouvez changer la dimension d’un tableau en cours de route si besoin. Cependant il faut être vigilent à ce que le nombre d’éléments soit cohérent avec la nouvelle dimension.
a = np.arange(6)
a
>>> [0 1 2 3 4 5]
a.shape
>>> (6,)
b = a.reshape(3, 2)
b
>>> array([[0, 1],
>>> [2, 3],
>>> [4, 5]])
b = np.reshape(a, (6,1))
b.shape
>>> (6, 1)
PythonLe premier exemple fonctionne car le nombre total d’éléments est cohérent avec la nouvelle dimension. Un vecteur de 6 éléments peut être modifié en une matrice de 3 lignes et 2 colonnes.
Le second exemple peut vous être pratique lorsqu’une fonction attend en entrée une matrice. Or, si votre cas est simple, vous êtes peut-être dans le cas où vous travaillez avec un vecteur et donc une dimension de type (n,). En utilisant la fonction « .reshape(n,1) » vous ajouterez une dimension et vous pourrez utiliser la fonction voulue.
Accéder aux valeurs et extraction
Pour accéder aux valeurs du tableau, il suffit d’utiliser les indices comme pour les listes. Voici quelques exemples :
# Création d'une matrice faite de nombre entier de type int8 entre 0 et 10 de manière aléatoire
# de taille 3 lignes 2 colonnes
matrice = np.random.randint(0, 10, size=(3, 2), dtype=np.int8)
matrice
>>> array([[7, 7],
>>> [5, 4],
>>> [9, 2]], dtype=int8)
matrice[2,1]
>>> 2
matrice[1:,1] # Extraction dans la colonne 2, de la ligne 2 jusqu'à la fin
>>> array([4, 2], dtype=int8)
matrice[1:] # Extraction de la ligne 2 jusqu'à la fin
>>> array([[5, 4],
>>> [9, 2]], dtype=int8)
PythonUne attention particulière est à porter si on stocke une portion d’un tableau dans une autre variable. En effet, on pourrait penser, moi le premier, que nous faisons une copie. Or, par défaut, ce n’est pas le cas pour des soucis de performance. La variable extraite est liée au tableau complet. Si vous souhaitez travailler sur un morceau d’un tableau et le modifier sans affecter le tableau d’origine, vous devrez faire une copie.
matrice = np.array([[1, 2, 3],[4, 5, 6]])
matrice
>>> array([[1, 2, 3],
>>> [4, 5, 6]])
a = matrice[:,1:] # Extraction de toutes les lignes, de la deuxième colonne jusqu'à la dernière
a
>>> array([[2, 3],
>>> [5, 6]])
a[0, 1] = 9
a # Notre sous-matrice a bien été modifée comme voulu.
>>> array([[2, 9],
>>> [5, 6]])
matrice # La matrice globale a été modifiée également !
>>> array([[1, 2, 9],
>>> [4, 5, 6]])
PythonPour éviter ce phénomène, vous pourrez alors utiliser la fonction « .copy() » qui permettra de modifier sans affecter la variable parent. J’attire toutefois votre attention sur le fait que cette pratique consommera plus de mémoire ! Mais si vous n’avez pas le choix, il faut bien entendu le faire.
matrice = np.array([[1, 2, 3],[4, 5, 6]])
a = matrice[:,1:].copy()
a[0, 1] = 9
a
>>> array([[2, 9],
>>> [5, 6]])
matrice # Cette fois-ci, la matrice globale n'est pas impactée.
>>> array([[1, 2, 3],
>>> [4, 5, 6]])
PythonLorsque vous travaillez sur un tableau, vous pouvez récupérer des éléments via des filtres. Vous obtiendrez alors un tableau avec les éléments qui respectent la condition. Voici un exemple :
matrice = np.array([[1, 2, 3],[4, 5, 6]])
matrice[matrice < 5]
>>> array([1, 2, 3, 4])
PythonUne autre façon de faire est de récupérer une matrice conditionnelle en fonction du filtre. Avec cette matrice, remplie de valeurs booléennes, vous pouvez alors afficher le résultat en croisant les deux. C’est une autre façon de travailler sur les filtres avec les matrices.
matrice = np.array([[1, 2, 3],[4, 5, 6]])
filtre = (matrice >= 5)
filtre
>>> array([[False, False, False],
>>> [False, True, True]])
matrice[filtre]
>>> array([5, 6])
PythonManipulation de plusieurs tableaux entre eux
Si vous souhaitez assembler plusieurs petits tableaux entre eux, vous avez les fonctions « concatenate », « hstack » et « vstack » qui pourront vous aider à construire un plus gros tableau.
a = np.array([1, 2])
b = np.array([3, 4])
c = np.array([5, 6])
np.concatenate((a,b,c))
>>> array([1, 2, 3, 4, 5, 6])
np.vstack((a,b,c))
>>> array([[1, 2],
>>> [3, 4],
>>> [5, 6]])
d = np.vstack((a,b))
e = np.vstack((a,c))
f = np.hstack((d,e))
>>> array([[1, 2, 1, 2],
>>> [3, 4, 5, 6]])
np.concatenate((d,e), axis=1) # Equivalent à np.hstack((d,e))
>>> array([[1, 2, 1, 2],
>>> [3, 4, 5, 6]])
np.concatenate((d,e)) # Equivalent à np.vstack((d,e))
array([[1, 2],
[3, 4],
[1, 2],
[5, 6]])
PythonOpérations sur les tableaux
Les opérations de bases sont disponibles sur les tableaux à condition que les dimensions sont cohérentes bien sûr.
tableau = np.array([1, 2]) # Création d'un tableau à 1 colonne, deux lignes.
tab_unitaire = np.ones(2, dtype=int) # Création d'un tableau à 1 colonne deux lignes rempli de 1.
tableau + tab_unitaire
>>> array([2, 3]) # 1 + 1 sur la première, et 2 + 1 sur la seconde.
tableau - tab_unitaire
>>> array([0, 1]) # 1 - 1 et 2 - 1
tableau * tableau
>>> array([1, 4]) # 1 * 1 et 2 * 2
tableau / tableau
>>> array([1., 1.])
Pythona = np.array([1, 2, 3, 4])
b = np.array([[1, 1], [2, 2]])
a.sum(), b.sum()
>>> (10, 6)
b.sum(axis=0), b.sum(axis=1)
>>> (array([3, 3]), array([2, 4]))
a * 2
>>> array([2, 4, 6, 8])
PythonEnfin, voici d’autres opérations plus avancées et toujours plus utiles :
matrice = np.array([[1, 2, 3],[4, 5, 6]])
matrice.min(), matrice.max()
>>> (1, 6)
matrice.min(axis=0)
>>> array([1, 2, 3])
matrice.max(axis=1)
>>> array([3, 6])
a = np.array([1, 2, 2, 4, 6, 6, 8, 8, 9, 10, 11, 11])
np.unique(a)
>>> array([ 1, 2, 4, 6, 8, 9, 10, 11])
liste_unique, liste_indices = np.unique(a, return_index=True)
liste_indices
>>> array([ 0, 1, 3, 4, 6, 8, 9, 10], dtype=int64)
PythonOpérations matricielles
Si vous travaillez avec des matrices, vous souhaiterez certainement réaliser des opérations dessus
a = np.array([[1, 2], [3, 4]])
b = np.array([[10, 20], [30, 40]])
print(a)
>>> [[1 2]
>>> [3 4]]
print(b)
>>> [[10 20]
>>> [30 40]]
print(a + b) # Addition des termes un à un
>>>[[11 22]
>>> [33 44]]
print(a * b) # Produit des termes des deux tableaux pour chaque chaque indice un à un
>>> [[ 10 40]
>>> [ 90 160]]
print(a.T) # Transposée de la matrice
>>> [[1 3]
>>> [2 4]]
print(np.dot(a,b)) # Produit matriciel
>>> [[ 70 100]
>>> [150 220]]
print(np.linalg.multi_dot([a, b, a])) # Produit matriciel de plusieurs matrices, écriture condensée
>>> [[ 370 540]
>>> [ 810 1180]]
print(np.linalg.inv(a)) # Inversion de la matrice
>>> [[-2. 1. ]
>>> [ 1.5 -0.5]]
print(np.linalg.det(a)) # Calculer le déterminant de la matrice
>>> -2.0000000000000004
print(np.linalg.eigvals(a)) # Calculer les valeurs propres de la matrice
>>> [-0.37228132 5.37228132]
PythonPour conclure sur cette section, vous avez pu voir les principales opérations sur les matrices. Beaucoup d’autres opérations sont également disponibles comme le calcul de la trace et des vecteurs propres. Cependant je me suis contenté ici des opérations principales. Je vous invite à parcourir la documentation si vous souhaitez plus d’informations.
Import / export de vos tableaux
Enregistrer vos tableaux peut être une pratique utile si vous ne voulez recommencer de zéro à chaque ou si vous souhaitez partager vos résultats. La bibliothèque NumPy propose sont propre format mais vous pourrez exporter les données en fichier texte ou CSV.
a = np.array([1, 2, 3, 4, 5, 6])
np.save('filename', a) # Sauvegarde du tableau dans le fichier “filename.npy”.
b = np.load('filename.npy')
print(b)
>>> [1 2 3 4 5 6]
PythonVous trouverez dans l’exemple suivant comment sauvegarder en fichier csv ou fichier texte (txt).
a = np.array([1, 2, 3, 4, 5, 6, 7, 8])
np.savetxt('new_file.csv', a)
np.loadtxt('new_file.csv')
>>> array([1., 2., 3., 4., 5., 6., 7., 8.])
PythonAvec la foncion « savetxt », vous pouvez définir une entête, le caractère délimitant et même des commentaires qui seront rajoutés dans le fichier lors de son écriture. Egalement, vous pouvez définir le format des nombres qui seront écrits avec l’argument « fmt ». Voici un exemple issu de la documentation:
x = y = z = np.arange(0.0,5.0,1.0)
np.savetxt('test.out', x, delimiter=',') # X est le tableau à sortir
np.savetxt('test.out', (x,y,z)) # x,y,z sont des tableaux de taille identique
np.savetxt('test.out', x, fmt='%1.4e') # Les valeurs seront écrites au format scientifique
PythonPour finir sur les import / export, les fichiers textes et CSV sont plus faciles à partager mais les fichier NPY, natif de la bibliothèque NumPy, seront plus petits et plus rapides à lire.
Pour finir sur cette introduction à la bibliothèque NumPy
Nous avons pu voir dans cet article comment utiliser la bibliothèque NumPy en Python pour travailler sur les vecteurs et les matrices. Cette bibliothèque offre des performances intéressantes pour le calcul scientifique.
Nous avons vu ensemble plusieurs cas d’application avec les fonctions les plus utiles. Je vous invite à aller fouiller dans la documentation pour découvrir d’autres fonctions.
Enfin, avec les tableaux vous pourrez également tracer toute sorte de graphiques via la librairie MatPlotLib. Egalement, les tableaux sont compatibles avec les structures « dataframe » de la librairie Pandas. Ces deux bibliothèques feront l’objet d’un article.
Merci de m’avoir lu, n’hésitez pas à mettre un commentaire, merci d’avance.
A bientôt, Benjamin