NumPy est une bibliothèque puissante pour le calcul scientifique en Python qui fournit des structures de données pour stocker et manipuler des tableaux multidimensionnels, tels que des vecteurs et des matrices. Il existe plusieurs moyens pour produire des vecteurs ou des matrices NumPy. Etudions, une à une, quelques unes de ces possibilités.
Ce premier exemple de code, vous montre comment créer un vecteur à partir d'une liste Python (vous pouvez remplacer la liste par un tuple).
import numpy as np
v = np.array([10, 20, 30, 40, 50])
print(type(v), v)
print("Taille du vecteur:", v.shape, v.size)
print(v[0], v[1], v[2], "...") # L'indice du premier élément d'un tableau NumPy est toujours 0 !!!
for value in v:
print(value)
<class 'numpy.ndarray'> [10 20 30 40 50] Taille du vecteur: (5,) 5 10 20 30 ... 10 20 30 40 50
Il est important de bien comprendre qu'un tel vecteur ne peut contenir que des données de même type. Attention, chaque type NumPy occupe un nombre d'octets bien précis : si vous tentez d'affecter une donnée plus grande que l'espace mémoire disponible, une erreur sera produite. Dans le cas du stockage d'un flottant dans un tableau NumPy d'entiers, la valeur flottante sera tronquée.
import numpy as np
v = np.array([10, 20, 30, 40, 50])
print("Data type:", v.dtype) # Le type np.int64 est déduit des types de la liste d'origine
v[2] = 2 ** 100 # L'entier ne tient pas sur 8 octets (64 bits).
Data type: int64
--------------------------------------------------------------------------- OverflowError Traceback (most recent call last) Cell In[2], line 5 3 v = np.array([10, 20, 30, 40, 50]) 4 print("Data type:", v.dtype) # Le type np.int64 est déduit des types de la liste d'origine ----> 5 v[2] = 2 ** 100 # L'entier ne tient pas sur 8 octets (64 bits). OverflowError: Python int too large to convert to C long
v[2] = "Juste pas possible, seuls des entiers sont supportés"
--------------------------------------------------------------------------- ValueError Traceback (most recent call last) Cell In[3], line 1 ----> 1 v[2] = "Juste pas possible, seuls des entiers sont supportés" ValueError: invalid literal for int() with base 10: 'Juste pas possible, seuls des entiers sont supportés'
v[2] = 3.14
print(v[2]) # Le flottant est tronqué car le vecteur contient des entiers
3
Si la liste iniitale contient au moins une valeur floattante, le type des données stockées dans le vecteur s'adapatera.
v = np.array([10, 20, 30.1, 40, 50])
print(type(v), v)
v[2] = np.pi
print(v) # Notez que l'affichage s'adapte à la taille de la plus grande données.
<class 'numpy.ndarray'> [10. 20. 30.1 40. 50. ] [10. 20. 3.14159265 40. 50. ]
Vous pouvez aussi pour une matrice de dimension quelconque. Dans ce premier exemple, je vous propose une matrice de dimension 2.
m = np.array([[10, 20, 30], [40, 50, 60], [70, 80, 90]])
print("Type de l'objet matrice :", type(m))
print("Nombre de dimensions de la matrice :", m.ndim)
print("Forme de la matrice :", m.shape)
print("Nombre total d'éléments dans la matrice :", m.size)
print("Type des données de la matrice :", m.dtype)
print(m)
Type de l'objet matrice : <class 'numpy.ndarray'> Nombre de dimensions de la matrice : 2 Forme de la matrice : (3, 3) Nombre total d'éléments dans la matrice : 9 Type des données de la matrice : int64 [[10 20 30] [40 50 60] [70 80 90]]
Rappel : on parle du type ndarray (n dimensionnal array). Il en découle que vous pouvez utiliser l'opérateur d'indexation avec autant de dimensions que souhaité.
value = m[1][1] # Ici on récupère la seconde ligne (on est indéxé à partir de 0) pour la seconde valeur de cette ligne
print(value)
value = m[1, 1] # Mais on peut aussi directement accéder à la valeur souhaitée.
print(value)
m[1, 1] = 5000
print(m)
50 50 [[ 10 20 30] [ 40 5000 60] [ 70 80 90]]
Un peu à la manière de la générateur python range
, vous pouvez utiliser la fonction np.arange
pour produire tableau avec des valeurs espacées régulière avec un pas donné. Cette fonction accepte jusqu'à trois paramètres : la valeur de dépard, la valeur de fin (exclusive) et le pas (par défaut 1). Contrairement au range
de Python (qui n'accepte que des entiers), cette fonction NumPy accepte des paramètres flottants. Voici un exemple d'utilisation.
x = np.arange(-np.pi, np.pi, 0.5)
print(x)
[-3.14159265 -2.64159265 -2.14159265 -1.64159265 -1.14159265 -0.64159265 -0.14159265 0.35840735 0.85840735 1.35840735 1.85840735 2.35840735 2.85840735]
Une autre solution serait d'utiliser la fonction np.linspace
. Contrairement à np.arange
qui attend un pas (un step), la function linspace
requière le nombre de mesure à produire. Voici un exemple d'utilisation.
x = np.linspace(-np.pi, np.pi, 13) # Notez que maintenant le point final est inclue
print(x)
[-3.14159265 -2.61799388 -2.0943951 -1.57079633 -1.04719755 -0.52359878 0. 0.52359878 1.04719755 1.57079633 2.0943951 2.61799388 3.14159265]
Voici quasiment le même exemple, couplé à l'utilisation de MatPlotLib.
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(-np.pi, np.pi, 1_000) # x est un vecteur de 1 000 mesures.
y = np.sin(x) # y est de même dimension et contient des sinus.
print(x.shape, y.shape)
plt.plot(x, y, label="Courbe Sinus")
plt.grid()
plt.legend()
plt.show()
(1000,) (1000,)
La fonction np.zeros
permet de produire un vecteur, ou une matrice, ne contenant que des valeurs 0
. Bien entendu, vous pouvez contrôler le type des données de votre tableau.
v = np.zeros((5,))
print(v.dtype, v)
v2 = np.zeros((5,), dtype=np.int64)
print(v2.dtype, v2)
m = np.zeros((10, 10))
print(m.dtype, m, sep="\n")
m2 = np.zeros((10, 10), dtype=np.uint8) # Chaque donnée n'occupera qu'un unique octet (non signé) en mémoire.
print(m2.dtype, m2, sep="\n")
float64 [0. 0. 0. 0. 0.] int64 [0 0 0 0 0] float64 [[0. 0. 0. 0. 0. 0. 0. 0. 0. 0.] [0. 0. 0. 0. 0. 0. 0. 0. 0. 0.] [0. 0. 0. 0. 0. 0. 0. 0. 0. 0.] [0. 0. 0. 0. 0. 0. 0. 0. 0. 0.] [0. 0. 0. 0. 0. 0. 0. 0. 0. 0.] [0. 0. 0. 0. 0. 0. 0. 0. 0. 0.] [0. 0. 0. 0. 0. 0. 0. 0. 0. 0.] [0. 0. 0. 0. 0. 0. 0. 0. 0. 0.] [0. 0. 0. 0. 0. 0. 0. 0. 0. 0.] [0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]] uint8 [[0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0]]
Si vous préférez, vous pouvez créer un tableau (vecteur ou matrice) avec que des 1
en utilisant la fonction np.ones
. Voici quelques exemples.
v = np.ones((5,))
print(v)
m = np.ones((5, 5))
print(m)
[1. 1. 1. 1. 1.] [[1. 1. 1. 1. 1.] [1. 1. 1. 1. 1.] [1. 1. 1. 1. 1.] [1. 1. 1. 1. 1.] [1. 1. 1. 1. 1.]]
Vous pouvez encore utiliser la fonction np.full
: celle-ci prend en second paramètre la valeur à utiliser pour l'initialisation du vecteur ou de la matrice.
v = np.full((5,), 123)
print(v)
m = np.full((5, 5), 123, dtype=np.int32)
print(m)
[123 123 123 123 123] [[123 123 123 123 123] [123 123 123 123 123] [123 123 123 123 123] [123 123 123 123 123] [123 123 123 123 123]]
Le sous modèle numpy.random
permet notamment de produire de tableaux initialisés avec des valeurs aléatoires. Regardons quelques exemples.
m = np.random.randint(0, 10, (5, 5), dtype=np.int32) # 0, 10 correspondent aux bornes, la borne maximale étant exclusive.
print(m)
[[1 0 9 8 9] [1 1 8 5 6] [2 1 5 3 6] [7 2 3 2 8] [8 8 1 8 0]]
Comme nous l'avons vu dans plusieurs exemples précédents, on spécifie souvent la taille de la matrice à produire via un tuple. Malheureusement, ce n'est pas toujours le cas, et voici justement un exemple ou il faut faire attention : la fonction np.random.rand
accepte les tailles du tableau à produire sous forme de paramètres positionnels :-( Il faudra se méfier sur ce point.
m = np.random.rand(5, 5)
print(m)
[[0.69181587 0.60209928 0.67523101 0.20147979 0.85665018] [0.02934067 0.12949007 0.36598856 0.5940865 0.94343049] [0.36693536 0.30445629 0.04962594 0.00104717 0.25859254] [0.42321217 0.18286818 0.26830758 0.62685933 0.30409083] [0.68661295 0.09406458 0.58609633 0.68846953 0.57360073]]
La fonction np.random.randn
permet de générer des valeurs aléatoires à partir d'une distribution gaussienne une distibution normale standard, avec une moyenne de 0 et une variance de 1).
m = np.random.randn(5, 5)
print(m)
[[-0.95947327 -0.35738242 3.02485142 1.97840666 1.46700397] [-0.43775434 -1.0168221 1.70325072 1.14702706 0.0155934 ] [ 1.47155763 0.81739475 1.24978173 -0.26416787 -1.60858914] [ 0.65886114 0.80815936 0.41646487 0.54625902 -0.30917607] [-1.39195839 0.14617855 1.07831663 0.67774898 -0.34793096]]
L'exemple suivant permet d'ajouter un peu de bruit à une fonction affine.
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(-10, 10, 20)
y = 3 * x - 2 # Notre fonction affine de base.
noise = np.random.randn(20) # On génère un bruit aléatoire
print(noise)
y2 = y + 5 * noise # On multiplie le bruit par 5 (pour toutes les valeurs) et on l'ajoute à y (terme à terme).
plt.plot(x, y, label="Une fonction affine")
plt.scatter(x, y2, c="red", label="La fonction avec le bruit")
plt.grid()
plt.legend()
plt.show()
[ 0.77792227 -0.78120673 -1.56265972 -0.14305115 0.9859095 -0.0709298 0.15422133 -0.83810824 -0.5593577 -0.2404528 0.99306941 -0.13350747 0.07927868 -1.16486328 0.23254927 -0.4821172 -0.84202893 0.10748221 -0.32698174 0.41496636]