9 Introduction à Numpy
Ce chapitre est consacré à une librairie importante pour les calculs numérique : NumPy
(abréviation de Numerical Python).
Il est coutume d’importer NumPy
en lui attribuant l’alias np
:
import numpy as np
9.1 Tableaux
NumPy propose une structure de données populaire, les tableaux (de type array), sur lesquels il est possible d’effectuer de manière efficace des calculs. Les tableaux sont une structure notamment utile pour effectuer des opérations statistiques basiques ainsi que de la génération pseudo-aléatoire de nombres.
La stucture des tableaux ressemble à celle des listes, mais ces dernières sont moins rapides à être traitées et utilisent davantage de mémoire. Le gain de vitesse de traitement des tableaux en NumPy
vient du fait que les données sont stockées dans des blocs contigus de mémoire, facilitant ainsi les accès en lecture.
Pour s’en convaincre, on peut reprendre l’exemple de Pierre Navaro donné dans son notebook sur NumPy
. Créons deux listes de longueur 1000 chacune, avec des nombres tirés aléatoirement à l’aide de la fonction random()
du module random
. Divisons chaque élément de la première liste par l’élément à la même position dans la seconde ligne, puis calculons la somme de ces 1000 divisions. Regardons ensuite le temps d’exécution à l’aide de la fonction magique %timeit
:
from random import random
from operator import truediv
l1 = [random() for i in range(1000)]
l2 = [random() for i in range(1000)]
# %timeit s = sum(map(truediv,l1,l2))
(décommenter la dernière ligne et tester sur un Jupyter Notebook)
À présent, transformons les deux listes en tableaux NumPy
avec la méthode array()
, et effectuons le même calcul à l’aide d’une méthode NumPy
:
a1 = np.array(l1)
a2 = np.array(l2)
# %timeit s = np.sum(a1/a2)
Comme on peut le constater en exécutant ces codes dans un environnement IPython, le temps d’exécution est bien plus rapide avec les méthodes de NumPy
pour ce calcul.
9.1.1 Création
La création d’un tableau peut s’effectuer avec la méthode array()
, à partir d’une liste, comme nous venon de le faire :
liste = [1,2,4]
tableau = np.array(liste)
print(tableau)
## [1 2 4]
print(type(tableau))
## <class 'numpy.ndarray'>
Si on fournit à array()
une liste de listes imbriquées de même longueur, un tableau multidimensionnel sera créé :
liste_2 = [ [1,2,3], [4,5,6] ]
tableau_2 = np.array(liste_2)
print(tableau_2)
## [[1 2 3]
## [4 5 6]]
print(type(tableau_2))
## <class 'numpy.ndarray'>
Les tableaux peuvent aussi être créés à partir de n-uplets :
nuplet = (1, 2, 3)
tableau = np.array(nuplet)
print(tableau)
## [1 2 3]
print(type(tableau))
## <class 'numpy.ndarray'>
Un tableau en dimension 1 peut être changé en tableau en dimension 2 (si possible), en modifiant son attribut shape
:
tableau = np.array([3, 2, 5, 1, 6, 5])
tableau.shape = (3,2)
print(tableau)
## [[3 2]
## [5 1]
## [6 5]]
9.1.1.1 Quelques fonctions générant des array
Certaines fonctions de NumPy
produisent des tableaux pré-remplis. C’est le cas de la fonction zeros()
. Quand on lui fournit une valeur entière \(n\), la fonction zeros()
créé un tableau à une dimension, avec \(n\) 0 :
print( np.zeros(4) )
## [0. 0. 0. 0.]
On peut préciser le type des zéros (par exemple int
, int32
, int64
, float
, float32
, float64
, etc.), à l’aide du paramètre dtype
:
print( np.zeros(4, dtype = "int") )
## [0 0 0 0]
D’avantage d’explications sur les types de données avec NumPy
sont disponibles sur la documentation en ligne.
Le type des éléments d’un tableau est indiqué dans l’attribut dtype
:
x = np.zeros(4, dtype = "int")
print(x, x.dtype)
## [0 0 0 0] int64
Il est par ailleurs possible de convertir le type des éléments dans un un autre type, à l’aide de la méthode astype()
:
y = x.astype("float")
print(x, x.dtype)
## [0 0 0 0] int64
print(y, y.dtype)
## [0. 0. 0. 0.] float64
Quand on lui fournit un n-uplet de longueur supérieure à 1, zeros()
créé un tableau à plusieurs dimensions :
print( np.zeros((2, 3)) )
## [[0. 0. 0.]
## [0. 0. 0.]]
print( np.zeros((2, 3, 4)) )
## [[[0. 0. 0. 0.]
## [0. 0. 0. 0.]
## [0. 0. 0. 0.]]
##
## [[0. 0. 0. 0.]
## [0. 0. 0. 0.]
## [0. 0. 0. 0.]]]
La fonction empty()
de Numpy
retourne également un tableau sur le même principe que zeros()
, mais sans initialiser les valeurs à l’intérieur.
print( np.empty((2, 3), dtype = "int") )
## [[0 0 0]
## [0 0 0]]
La fonction ones()
de Numpy
retourne le même genre de tableaux, avec des 1 en valeurs initialisées :
print( np.ones((2, 3), dtype = "float") )
## [[1. 1. 1.]
## [1. 1. 1.]]
Pour choisir une valeur spécifique pour l’initialisation, on peut utiliser la fonction full()
de Numpy
:
print( np.full((2, 3), 10, dtype = "float") )
## [[10. 10. 10.]
## [10. 10. 10.]]
print( np.full((2, 3), np.inf) )
## [[inf inf inf]
## [inf inf inf]]
La fonction eye()
de Numpy
créé un tableau à deux dimensions dans laquelle tous les éléments sont initalisés à zéro, sauf ceux de la diagonale initialisés à 1 :
print( np.eye(2, dtype="int64") )
## [[1 0]
## [0 1]]
En modifiant le paramètre mot-clé k
, on peut décaler la diagonale :
print( np.eye(3, k=-1) )
## [[0. 0. 0.]
## [1. 0. 0.]
## [0. 1. 0.]]
La fonction identity()
de Numpy
créé quant à elle une matrice identité sous la forme d’un tableau :
print( np.identity(3, dtype = "int") )
## [[1 0 0]
## [0 1 0]
## [0 0 1]]
La fonction arange()
de Numpy
permet de générer une séquence de nombres séparés par un interval fixe, le tout stocké dans un tableau. La syntaxe est la suivante :
np.arange( start, stop, step, dtype )
avec start
la valeur de départ, stop
celle d’arrivée, step
le pas, l’espacement entre les nombres de la séquence et dtype
le type des nombres :
print( np.arange(5) )
## [0 1 2 3 4]
print( np.arange(2, 5) )
## [2 3 4]
print( np.arange(2, 10, 2) )
## [2 4 6 8]
9.1.2 Dimensions
Pour connaître la dimension d’un tableau, on peut afficher la valeur de l’attribut ndim
:
print("ndim tableau : ", tableau.ndim)
## ndim tableau : 2
print("ndim tableau_2 : ", tableau_2.ndim)
## ndim tableau_2 : 2
Le nombre d’éléments dans le tableau peut s’obtenir par l’attribut size
ou par la fonction size()
de Numpy
:
print("size tableau : ", tableau.size)
## size tableau : 6
print("size tableau_2 : ", tableau_2.size)
## size tableau_2 : 6
print("np.size(tableau) :", np.size(tableau))
## np.size(tableau) : 6
L’attribut shape
retourne un n-uplet indiquant la longueur pour chaque dimension du tableau :
print("size tableau : ", tableau.shape)
## size tableau : (3, 2)
print("size tableau_2 : ", tableau_2.shape)
## size tableau_2 : (2, 3)
9.1.3 Extraction des éléments d’un tableau
L’accès aux éléments d’un tableau se fait de la même manière que pour les listes (c.f. Section 3.1.1), grâce à l’indiçage. La syntaxe est la suivante :
tableau[lower:upper:step]
avec lower
la borne inférieur de la plage d’indices, upper
la plage supérieur, et step
l’espacement entre les valeurs.
- Lorsque
lower
n’est pas précisé, le premier élément (indicé 0) est considéré comme la valeur attribuée àlower
. - Lorsque
upper
n’est pas précisé, le dernier élément est considéré comme la valeur attribuée àupper
. - Lorsque
step
n’est pas précisé, un pas de 1 est attribué par défaut.
Reprenons rapidement quelques exemples, en s’appuyant sur deux objets : un tableau de dimension 1, et un second de dimension 2.
tableau_1 = np.arange(1,13)
tableau_2 = [ [1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]
tableau_2 = np.array(tableau_2)
L’accès au premier élément :
message = "tableau_{}[0] : {} (type : {})"
print(message.format(0, tableau_1[0], type(tableau_1[0])))
## tableau_0[0] : 1 (type : <class 'numpy.int64'>)
print(message.format(1, tableau_2[0], type(tableau_2[0])))
## tableau_1[0] : [1 2 3] (type : <class 'numpy.ndarray'>)
L’accès aux éléments peut se faire en partant par la fin :
print("tableau_1[-1] : ", tableau_1[-1]) # dernier élément
## tableau_1[-1] : 12
print("tableau_2[-1] : ", tableau_2[-1]) # dernier élément
## tableau_2[-1] : [10 11 12]
Le découpage est possible :
# les éléments du 2e (non inclus) au 4e
print("Slice Tableau 1 : \n", tableau_1[2:4])
## Slice Tableau 1 :
## [3 4]
print("Sclie Tableau 2 : \n", tableau_2[2:4])
## Sclie Tableau 2 :
## [[ 7 8 9]
## [10 11 12]]
Pour les tableaux à deux dimensions, on peut accéder aux éléments de la manière suivante, de manière équivalente :
# Dans le 3e élément, accéder au 1er élément
print(tableau_2[2][0])
## 7
print(tableau_2[2,0])
## 7
Pour extraire des colonnes d’un tableau à deux entrées :
print("Deuxième colonne : \n", tableau_2[:, [1]])
## Deuxième colonne :
## [[ 2]
## [ 5]
## [ 8]
## [11]]
print("Deuxièmes et troisièmes colonnes : \n", tableau_2[:, [1,2]])
## Deuxièmes et troisièmes colonnes :
## [[ 2 3]
## [ 5 6]
## [ 8 9]
## [11 12]]
Pour cette dernière instruction, on indique avec le premier paramètre non renseigné (avant les deux points) que l’on désire tous les éléments de la première dimension, puis, avec la virgule, on indique qu’on regarde à l’intérieur de chaque élément de la première dimension, et qu’on veut les valeurs aux positions 1 et 2 (donc les éléments des colonnes 2 et 3).
Pour extraire seulement certains éléments d’un tableau à 1 dimension, on peut indiquer les indices des éléments à récupérer :
print("2e et 4e éléments : \n", tableau_2[[1,3]])
## 2e et 4e éléments :
## [[ 4 5 6]
## [10 11 12]]
9.1.3.1 Extraction à l’aide de booléens
Pour extraire ou non des éléments d’un tableu, on peut utiliser des tableaux de booléens en tant que masques. L’idée est de fournir un tableau de booléens (un masque) de même dimension que celui pour lequel on désire extraire des éléments sous certaines conditions. Lorsque la valeur du booléen dans le masque vaut True
, l’élément correspondant du tableau est retourné ; sinon, il ne l’est pas.
tableau = np.array([0, 3, 2, 5, 1, 4])
res = tableau[[True, False, True, False, True, True]]
print(res)
## [0 2 1 4]
Seuls les éléments en position 1, 3, 5 et 6 on été retournés.
En pratique, le masque n’est que très rarement créé par l’utilisateur, il est plutôt issu d’une instruction logique appliquée au tableau d’intérêt. Par exemple, dans notre tableau, nous pouvons dans un premier temps créer un masque de manière à identifier les éléments pairs :
masque = tableau % 2 == 0
print(masque)
## [ True False True False False True]
print(type(masque))
## <class 'numpy.ndarray'>
Une fois ce masque créé, on peut l’appliquer au tableau pour extraire uniquement les éléments pour lesquels la valeur correspondante dans le masque vaut True
:
print(tableau[masque])
## [0 2 4]
9.1.4 Modification
Pour remplacer les valeurs d’un tableau, on utilise le signe égal (=
) :
tableau = np.array([ [1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]])
tableau[0] = [11, 22, 33]
print(tableau)
## [[11 22 33]
## [ 4 5 6]
## [ 7 8 9]
## [10 11 12]]
Si on fournit un scalaire lors du remplacement, la valeur sera répétée pour tous les éléments de la dimension :
tableau[0] = 100
print(tableau)
## [[100 100 100]
## [ 4 5 6]
## [ 7 8 9]
## [ 10 11 12]]
Idem avec un découpage :
tableau[0:2] = 100
print(tableau)
## [[100 100 100]
## [100 100 100]
## [ 7 8 9]
## [ 10 11 12]]
D’ailleurs, un découpage avec juste les deux points sans préciser les paramètres de début et de fin du découpage suivi d’un signe égal et d’un nombre remplace toutes les valeurs du tableau par ce nombre :
tableau[:] = 0
print(tableau)
## [[0 0 0]
## [0 0 0]
## [0 0 0]
## [0 0 0]]
9.1.4.1 Ajout d’éléments
Pour ajouter des éléments, on utilise la fonction append()
de NumPy
. Il faut noter que l’appel à cette fonction ne modifie pas l’objet auquel on ajoute les valeurs. Si on désire que les modifications sont apportées à cet objet, il faut l’écraser :
t_1 = np.array([1,3,5])
print("t_1 : ", t_1)
## t_1 : [1 3 5]
t_1 = np.append(t_1, 1)
print("t_1 après l'ajout : ", t_1)
## t_1 après l'ajout : [1 3 5 1]
Pour ajouter une colonne à un tableau à deux dimensions :
t_2 = np.array([[1,2,3], [5,6,7]])
print("t_2 : \n", t_2)
## t_2 :
## [[1 2 3]
## [5 6 7]]
ajout_col_t_2 = np.array([[4], [8]])
t_2 = np.append(t_2,ajout_col_t_2, axis = 1)
print("t_2 après ajout colonne : \n", t_2)
## t_2 après ajout colonne :
## [[1 2 3 4]
## [5 6 7 8]]
Pour ajouter une ligne, on utilise la fonction vstack()
de Numpy
:
ajout_ligne_t_2 = np.array([10, 11, 12, 13])
t_2 = np.vstack([t_2,ajout_ligne_t_2])
print("t_2 après ajout ligne : \n", t_2)
## t_2 après ajout ligne :
## [[ 1 2 3 4]
## [ 5 6 7 8]
## [10 11 12 13]]
9.1.4.2 Suppression d’éléments
Pour supprimer des éléments, on utilise la fonction delete()
de NumPy
:
print("t_1 : ", t_1)
# Supprimer le dernier élément
## t_1 : [1 3 5 1]
np.delete(t_1, (-1))
Note : pour que la suppression soit effective, on assigne le résultat de np.delete()
à l’objet.
Pour supprimer plusieurs éléments :
print("t_1 : ", t_1)
# Supprimer les 1er et 2e éléments
## t_1 : [1 3 5 1]
t_1 = np.delete(t_1, ([0, 2]))
print(t_1)
## [3 1]
Pour supprimer une colonne d’un tableau à deux dimensions :
print("t_2 : ", t_2)
# Supprimer la première colonne :
## t_2 : [[ 1 2 3 4]
## [ 5 6 7 8]
## [10 11 12 13]]
np.delete(t_2, (0), axis=1)
Supprimer plusieurs colonnes :
print("t_2 : ", t_2)
# Supprimer la 1ère et la 3e colonne :
## t_2 : [[ 1 2 3 4]
## [ 5 6 7 8]
## [10 11 12 13]]
np.delete(t_2, ([0,2]), axis=1)
Et pour supprimer une ligne :
print("t_2 : ", t_2)
# Supprimer la première ligne :
## t_2 : [[ 1 2 3 4]
## [ 5 6 7 8]
## [10 11 12 13]]
np.delete(t_2, (0), axis=0)
Supprimer plusieurs lignes :
print("t_2 : ", t_2)
# Supprimer la 1ère et la 3e ligne
## t_2 : [[ 1 2 3 4]
## [ 5 6 7 8]
## [10 11 12 13]]
np.delete(t_2, ([0,2]), axis=0)
9.1.5 Copie de tableau
La copie d’un tableau, comme pour les listes (c.f. Section 3.1.4), ne doit pas se faire avec le symbole égal (=
).
tableau_1 = np.array([1, 2, 3])
tableau_2 = tableau_1
Modifions le premier élément de tableau_2
, et observons le contenu de tableau_2
et de tableau_1
:
tableau_2[0] = 0
print("Tableau 1 : \n", tableau_1)
## Tableau 1 :
## [0 2 3]
print("Tableau 2 : \n", tableau_2)
## Tableau 2 :
## [0 2 3]
Comme on peut le constater, le fait d’avoir utilisé le signe égal a simplement créé une référence et non pas une copie.
Pour effectuer une copie de tableaux, plusieurs façons existent. Parmi elles, l’utilisation de la fonction np.array()
:
tableau_1 = np.array([1, 2, 3])
tableau_2 = np.array(tableau_1)
tableau_2[0] = 0
print("tableau_1 : ", tableau_1)
## tableau_1 : [1 2 3]
print("tableau_2 : ", tableau_2)
## tableau_2 : [0 2 3]
On peut également utiliser la méthode copy()
:
tableau_1 = np.array([1, 2, 3])
tableau_2 = tableau_1.copy()
tableau_2[0] = 0
print("tableau_1 : ", tableau_1)
## tableau_1 : [1 2 3]
print("tableau_2 : ", tableau_2)
## tableau_2 : [0 2 3]
On peut noter que lorsque l’on fait un découpement, un nouvel objet est créé, pas une référence :
tableau_1 = np.array([1, 2, 3, 4])
tableau_2 = tableau_1[:2]
tableau_2[0] = 0
print("tableau_1 : ", tableau_1)
## tableau_1 : [0 2 3 4]
print("tableau_2 : ", tableau_2)
## tableau_2 : [0 2]
9.1.6 Tri
La librairie NumPy
fournit une fonction pour trier les tableaux : sort()
.
tableau = np.array([3, 2, 5, 1, 6, 5])
print("Tableau trié : ", np.sort(tableau))
## Tableau trié : [1 2 3 5 5 6]
print("Tableau : ", tableau)
## Tableau : [3 2 5 1 6 5]
Comme on peut le constater, la fonction sort()
de NumPy
propose une vue : le tableau n’est pas modifié, ce qui n’est pas le cas si on utilise la méthode sort()
:
tableau = np.array([3, 2, 5, 1, 6, 5])
tableau.sort()
print("Le tableau a été modifié : ", tableau)
## Le tableau a été modifié : [1 2 3 5 5 6]
9.1.7 Transposition
Pour obtenir la transposée d’un tableau, on fait appel à l’attribut T
. Il faut noter que l’on obtient une vue de l’objet, que cela ne le modifie pas.
tableau = np.array([3, 2, 5, 1, 6, 5])
tableau.shape = (3,2)
print("Tableau : \n", tableau)
## Tableau :
## [[3 2]
## [5 1]
## [6 5]]
print("Tableau transposé : \n", tableau.T)
## Tableau transposé :
## [[3 5 6]
## [2 1 5]]
On peut également utiliser la fonction transpose()
de NumPy
:
print(np.transpose(tableau))
## [[3 5 6]
## [2 1 5]]
Attention, si on assigne un nom à la transposée, que ce soit en utilisant l’attribut T
ou la méthode np.transpose()
, cela créé une référence, pas une copie d’élément…
tableau_transpose = np.transpose(tableau)
tableau_transpose[0,0] = 99
print("tableau : \n", tableau)
## tableau :
## [[99 2]
## [ 5 1]
## [ 6 5]]
print("tableau_transpose : \n", tableau_transpose)
## tableau_transpose :
## [[99 5 6]
## [ 2 1 5]]
Pour savoir si un tableau est une vue ou non, on peut afficher l’attribut base
, qui retourne None
si ce n’est pas le cas :
print("tableau : ", tableau.base)
## tableau : None
print("tableau_transpose : ", tableau_transpose.base)
## tableau_transpose : [[99 2]
## [ 5 1]
## [ 6 5]]
9.1.8 Opérations sur les tableaux
Il est possible d’utiliser des opérateurs sur les tableaux. Leur effet nécessite quelques explications.
9.1.8.1 Opérateurs +
et -
Lorsque l’opérateur +
(-
) est utilisé entre deux tableaux de même dimension, une addition (soustraction) terme à terme est effectuée :
t_1 = np.array([1, 2, 3, 4])
t_2 = np.array([5, 6, 7, 8])
t_3 = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])
t_4 = np.array([[13, 14, 15, 16], [17, 18, 19, 20], [21, 22, 23, 24]])
t_1 + t_2
t_3 + t_4
t_1 - t_2
Lorsque l’opérateur +
(-
) est utilisé entre un scalaire et un tableau, le scalaire est ajouté (soustrait) à tous les éléments du tableau :
print("t_1 + 3 : \n", t_1 + 3)
## t_1 + 3 :
## [4 5 6 7]
print("t_1 + 3. : \n", t_1 + 3.)
## t_1 + 3. :
## [4. 5. 6. 7.]
print("t_3 + 3 : \n", t_3 + 3)
## t_3 + 3 :
## [[ 4 5 6 7]
## [ 8 9 10 11]
## [12 13 14 15]]
print("t_3 - 3 : \n", t_3 - 3)
## t_3 - 3 :
## [[-2 -1 0 1]
## [ 2 3 4 5]
## [ 6 7 8 9]]
9.1.8.2 Opérateurs *
et /
Lorsque l’opérateur *
(/
) est utilisé entre deux tableaux de même dimension, une multiplication (division) terme à terme est effectuée :
t_1 * t_2
t_3 * t_4
t_3 / t_4
Lorsque l’opérateur *
(/
) est utilisé entre un scalaire et un tableau, tous les éléments du tableau sont multipliés (divisés) par ce scalaire :
print("t_1 * 3 : \n", t_1 * 3)
## t_1 * 3 :
## [ 3 6 9 12]
print("t_1 / 3 : \n", t_1 / 3)
## t_1 / 3 :
## [0.33333333 0.66666667 1. 1.33333333]
9.1.8.3 Puissance
Il est également possible d’élever chaque nombre d’un tableau à une puissance donnée :
print("t_1 ** 3 : \n", t_1 ** 3)
## t_1 ** 3 :
## [ 1 8 27 64]
9.1.8.4 Opérations sur des matrices
En plus des opérations/soustraction/multiplication/division terme à terme ou par un scalaire, il est possible d’effectuer certains calculs sur des tableaux à deux dimension.
Nous avons déjà vu la tranposée en Section 9.1.7.
Pour effectuer un produit matriciel, NumPy
fournit la fonction dot()
:
np.dot(t_3, t_4.T)
Il faut bien s’assurer d’avoir des matrices compatibles, sinon, une erreur sera retournée :
np.dot(t_3, t_4)
## ValueError: shapes (3,4) and (3,4) not aligned: 4 (dim 1) != 3 (dim 0)
##
## Detailed traceback:
## File "<string>", line 1, in <module>
Le produit matriciel peut également s’obtenir à l’aide de l’opérateur @
:
t_3 @ t_4.T
Le produit d’un vecteur avec une matrice est également possible :
np.dot(t_1, t_3.T)
9.1.9 Opérateurs logiques
Pour effectuer des tests logiques sur les éléments d’un tableau, NumPy
propose des fonctions, répertoriées dans le Tableau 9.1. Le résultat retourné par l’application de ces fonctions est un tableau de booléens.
Code | Description |
---|---|
greater() |
Supérieur à |
greater_equal() |
Supérieur ou égal à |
less() |
Inférieur à |
less_equal() |
Inférieur ou égal à |
equal() |
Égal à |
not_equal() |
Différent de |
logical_and() |
Et logique |
logical_or() |
Ou logique |
logical_xor() |
XOR logique |
Par exemple, pour obtenir les éléments de t
compris entre 10 et 20 (inclus) :
t = np.array([[1, 10, 3, 24], [9, 12, 40, 2], [0, 7, 2, 14]])
masque = np.logical_and(t <= 20, t >= 10)
print("masque : \n", masque)
## masque :
## [[False True False False]
## [False True False False]
## [False False False True]]
print("les éléments de t compris entre 10 et 20 : \n",
t[masque])
## les éléments de t compris entre 10 et 20 :
## [10 12 14]
9.1.10 Quelques constantes
NumPy
propose quelques constantes, dont certaines sont reportées dans le Tableau 9.2.
Code | Description |
---|---|
np.inf |
Infini (on obtient \(-\infty\) en écrivant -np.inf ou np.NINF ) |
np.nan |
Représentation en tant que nombre à virgule flottante de Not a Number |
np.e |
Constante d’Euler (\(e\)) |
np.euler_gamma |
Constante d’Euler-Mascheroni (\(\gamma\)) |
np.pi |
Nombre Pi (\(\pi\)) |
On peut noter la présence de la valeur NaN
, qui est une valeur spéciale parmi les nombres à virgule flottante. Le comportement de cette constante est spécial.
Quand on additionne, soustrait, multiplie ou divise un nombre par cette valeur NaN
, on obtient NaN
:
print("Addition : ", np.nan + 1)
## Addition : nan
print("Soustraction : ", np.nan - 1)
## Soustraction : nan
print("Multiplication : ", np.nan + 1)
## Multiplication : nan
print("AddDivisiontion : ", np.nan / 1)
## AddDivisiontion : nan
9.1.11 Fonctions universelles
Les fonctions universelles (ufunc pour universal functions) sont des fonctions qui peuvent être appliquées terme à terme aux éléments d’un tableau. On distingue deux types de fonctions universelles : les fonctions unaires, qui effectuent une opération sur une seule, et les fonctions binaires qui effectuent une opération sur deux opérandes.
Parmi les ufuncs, on retrouve des opérations arithmétiques (addition, multiplication, puissance, valeur absolue, etc.) et des fonctions mathématiques usuelles (fonctions trigonométriques, exponentielle, logarithme, etc.). Le Tableau 9.3 répertorie quelques fonctions universelles unaires, tandis que le Tableau 9.4 répertories quelques fonctions universelles binaires.
Code | Description |
---|---|
negative(x) |
Opposés des éléments de x |
absolute(x) |
Valeurs absolues des éléments de x |
sign(x) |
Signes des éléments de x (0, 1 ou -1) |
rint(x) |
Arrondi de x à l’entier |
floor(x) |
Troncature de x à l’entier inférieur |
ceil(x) |
Troncature de x à l’entier supérieur |
sqrt(x) |
Racine carrée de x |
square(x) |
Carré de x |
sin(x) , cos(x) , tan(x) |
Sinus (cosinus, et tangente) de x |
sinh(x) , cosh(x) , tanh(x) |
Sinus (cosinus, et tangente) hyperbolique de x |
arcsin(x) , arccos(x) , arctan(x) |
Arc-sinus (arc-cosinus, et arc-tangente) de x | | `arcsinh(x)`, `arccosh(x)`, `arctanh(x)` | Arc-sinus (arc-cosinus, et arc-tangente) hyperbolique de x |
hypoth(x,y) |
Hypoténuse \(\sqrt{x^2+y^2}\) |
degrees(x) |
Conversion des angles x de radians en degrés |
radians(x) |
Conversion des angles x de degrés en radians |
exp(x) |
Exponentielle de x |
expm1(x) |
\(e^x-1\) |
log(x) |
Logarithme népérien des éléments de x |
log10(x) |
Logatithme des éléments de x en base 10 |
log2(x) |
Logarithme des éléments de x en base 2 |
log1p(x) |
\(ln(1+x\) |
exp2(x) |
\(2^x\) |
isnan(x) |
Tableau de booléens indiquant True pour les éléments NaN |
isfinite(x) |
Tableau de booléens indiquant True pour les éléments non infinis et non-NaN |
isinf(x) |
Tableau de booléens indiquant True pour les éléments infinis |
Code | Description |
---|---|
add(x,y) |
Addition terme à terme de x et y |
subtract(x,y) |
Soustraction terme à terme de x et y |
multiply(x,y) |
Multiplication terme à terme de x et y |
divide(x,y) |
Division terme à terme de x et y |
floor_divide(x,y) |
Quotients entiers des divisions terme à terme de x et y |
power(x,y) |
Élévation des éléments de x à la puissance des éléments de y |
mod(x,y) |
Restes des divisions eucliennes des éléments de x par ceux de y |
round(x,n) |
Arrondi de x à \(n\) décimales |
arctan2(x,y) |
Angles polaires de x et y |
Pour utiliser ses fonctions, procéder comme dans l’exemple suivant :
t_1 = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])
t_2 = np.array([[13, 14, 15, 16], [17, 18, 19, 20], [21, 22, 23, 24]])
np.log(t_1) # Logarithme népérien
np.subtract(t_1, t_2) # Soustraction des éléments de t_1 par ceux de t_2
9.1.12 Méthodes et fonctions mathématiques et statistiques
NumPy
fournit de nombreuses méthodes pour calculer des statistiques sur l’ensemble des valeurs des tableaux, ou sur un des axes des tableaux (par exemple sur l’équivalent de lignes ou des colonnes dans les tableaux à deux dimensions). Certaines sont reportées dans le Tableau 9.5.
Code | Description |
---|---|
sum() |
Retourne la somme des éléments |
prod() |
Retourne le produit des éléments |
cumsum() |
Retourne la somme cumulée des éléments |
cumprod() |
Retourne le produit cumulé des éléments |
mean() |
Retourne la moyenne |
var() |
Retourne la variance |
std() |
Retourne l’écart-type |
min() |
Retourne la valeur minimale |
max() |
Retourne la valeur maximale |
argmin() |
Retourne l’indice du premier élément à la plus petite valeur |
argmax() |
Retourne l’indice du premier élément à la plus grande valeur |
Donnons un exemple de l’utilisation de ces méthodes :
t_1 = np.array([[1, 2, 3, 4], [-1, 6, 7, 8], [9, -1, 11, 12]])
print("t_1 : \n", t_1)
## t_1 :
## [[ 1 2 3 4]
## [-1 6 7 8]
## [ 9 -1 11 12]]
print("Somme des éléments : ", t_1.sum())
## Somme des éléments : 61
print("Covariance des éléments : ", t_1.var())
## Covariance des éléments : 18.07638888888889
Pour appliquer ces fonctions sur un axe donné, on modifie la valeur du paramètre axis
:
print("Somme par colonne: ", t_1.sum(axis=0))
## Somme par colonne: [ 9 7 21 24]
print("Somme par ligne: ", t_1.sum(axis=1))
## Somme par ligne: [10 20 31]
NumPy
offre aussi certaines fonctions spécifiques aux statistiques, dont certaines sont répertoriées dans le Tableau 9.6.
Code | Description |
---|---|
sum(x) , nansum(x) |
Somme de x (nansum(x) ne tient pas compte des valeurs NaN ) |
mean(x) , nanmean() |
Moyenne de x |
median(x) , nanmedian() |
Médiane de x |
average(x) |
Moyenne de x (possibilité d’utiliser des poids à l’aide du paramètre weight ) |
min(x) , nanmin() |
Minimum de x |
max(x) , nanmax() |
Maximum de x |
percentile(x,p) , nanpercentile(n,p) |
P-ème percentile de x |
var(x) , nanvar(x) |
Variance de x |
std(x) , nanstd() |
Écart-type de x |
cov(x) |
Covariance de x |
corrcoef(x) |
Coefficients de corrélation |
Pour utiliser les fonctions statistiques :
t_1 = np.array([[1, 2, 3, 4], [-1, 6, 7, 8], [9, -1, 11, 12]])
print("t_1 : \n", t_1)
## t_1 :
## [[ 1 2 3 4]
## [-1 6 7 8]
## [ 9 -1 11 12]]
print("Variance: ", np.var(t_1))
## Variance: 18.07638888888889
Si le tableau comporte des valeurs NaN
, pour calculer la somme par exempe, si on utilise sum()
, le résultat sera NaN
. Pour ignorer les valeurs NaN
, on utilise une fonction spécifique (ici, nansum()
) :
t_1 = np.array([[1, 2, np.NaN, 4], [-1, 6, 7, 8], [9, -1, 11, 12]])
print("somme : ", np.sum(t_1))
## somme : nan
print("somme en ignorant les NaN : ", np.nansum(t_1))
## somme en ignorant les NaN : 58.0
Pour calculer une moyenne pondérée (prenons un vecteur) :
v_1 = np.array([1, 1, 4, 2])
w = np.array([1, 1, .5, 1])
print("Moyenne pondérée : ", np.average(v_1, weights=w))
## Moyenne pondérée : 1.7142857142857142
9.2 Génération de nombres pseudo-aléatoires
La génération de nombres pseudo-aléatoires est permise par le module random
de Numpy
. Le lecteur intéressé par les aspects plus statistiques pourra trouver davantage de notions abordées dans le sous-module stats
de SciPy
.
from numpy import random
Le Tableau 9.7 répertorie quelques fonctions permettant de tirer de manière pseudo-aléatoire des nombres avec le module random
de Numpy
(en évaluant ??random
, on obtient une liste exhaustive).
Code | Description |
---|---|
rand(size) |
Tirage de size valeurs selon une Uniforme \([0,1]\) |
uniform(a,b,size) |
Tirage de size valeurs selon une Uniforme \([a ; b]\) |
randint(a,b,size) |
Tirage de size valeurs selon une Uniforme \([a ; b[\) |
randn(size) |
Tirage de size valeurs selon une Normale centrée réduite |
normal(mu, std, size) |
Tirage de size valeurs selon une Normale d’espérance mu et d’écart-type std |
binomial(size) |
Tirage de size valeurs selon une \(\mathcal{B}in(n,p)\) |
beta(alpha, beta, size) |
Tirage de size valeurs selon une loi bêta de paramètres alpha et beta |
poisson(lambda, size) |
Tirage de size valeurs selon une loi de Poisson de paramètre lambda |
f(size) |
Tirage de size valeurs selon une |
standard_t(df, size) |
Tirage de size valeurs selon une loi de Student à df degrés de liberté |
Voici un exemple de génération de nombres pseudo aléatoires selon une distribution Gaussienne :
x = np.random.normal(size=10)
print(x)
## [-0.21608437 -0.04763351 -0.91065944 -0.8920658 -1.20739158 0.6140933
## -0.79615403 -0.10350956 -0.7288215 1.46985647]
On peut générer un tableau à plusieurs dimensions. Par exemple, un tableau à deux dimensions, dans lequel la première dimension contient 10 éléments, contenant chacun 4 tirages aléatoires selon une \(\mathcal{N}(0,1)\) :
x = np.random.randn(10, 4)
print(x)
## [[ 0.0145722 -1.87532297 0.26389604 0.74479245]
## [ 0.21507124 0.37340081 -2.30198978 0.80505913]
## [ 0.47294127 -0.41094583 0.32768293 0.44436743]
## [ 0.78187322 -0.58665232 -0.5309845 0.04994529]
## [-0.18898402 -1.09015923 0.23203975 1.43007593]
## [-0.48374179 -0.62116834 1.92289637 1.04752284]
## [-1.03791008 0.57730921 0.57319431 0.9893094 ]
## [-1.83270058 0.49668076 -0.10631126 -0.74305415]
## [-1.34024884 -0.77796387 -0.50054115 1.77357994]
## [-0.20097655 -1.43614827 0.74681482 0.83931251]]
La génération des nombres s’effectue en fonction d’une graine (seed), c’est-à-dire un nombre initiant le générateur de nombres pseudo aléatoires. Il est possible de fixer cette graine, pour pouvoir avoir des résultats reproductibles par exemple. Pour ce faire, on peut faire appel à la méthode seed()
, à qui on indique une valeur en paramètre :
np.random.seed(1234)
x = np.random.normal(size=10)
print(x)
## [ 0.47143516 -1.19097569 1.43270697 -0.3126519 -0.72058873 0.88716294
## 0.85958841 -0.6365235 0.01569637 -2.24268495]
En fixant à nouveau la graîne, on obtiendra exactement le même tirage :
np.random.seed(1234)
x = np.random.normal(size=10)
print(x)
## [ 0.47143516 -1.19097569 1.43270697 -0.3126519 -0.72058873 0.88716294
## 0.85958841 -0.6365235 0.01569637 -2.24268495]
Pour éviter d’affecter l’environnement global par la graine aléatoire, on peut utiliser la méthode RandomState
du sous-module random
de NumPy
:
from numpy.random import RandomState
rs = RandomState(123)
x = rs.normal(10)
print(x)
## 8.914369396699438
Par ailleurs, la fonction permutation()
du sous-module random
permet d’effectuer une permutation aléatoire :
x = np.arange(10)
y = np.random.permutation(x)
print("x : ", x)
## x : [0 1 2 3 4 5 6 7 8 9]
print("y : ", y)
## y : [9 7 4 3 8 2 6 1 0 5]
La fonction shuffle()
du sous-module random
permet quant à elle d’effectuer une permutation aléatoire des éléments :
x = np.arange(10)
print("x avant permutation : ", x)
## x avant permutation : [0 1 2 3 4 5 6 7 8 9]
np.random.permutation(x)
print("x après permutation : ", x)
## x après permutation : [0 1 2 3 4 5 6 7 8 9]
9.3 Exercice
Premier exercice
Considérons le vecteur suivant : \(x = \begin{bmatrix}1 & 2 & 3 & 4 & 5\end{bmatrix}\)
- Créer ce vecteur à l’aide d’un tableau que l’on appellera
x
. - Afficher le type de
x
puis sa longueur. - Extraire le premier élément, puis en faire de même avec le dernier.
- Extraire les trois premiers éléments et les stocker dans un vecteur que l’on nommera
a
. - Extraire les 1er, 2e et 5e éléments du vecteur (attention aux positions) ; les stocker dans un vecteur que l’on nommera
b
. - Additionner le nombre 10 au vecteur
x
, puis multiplier le résultat par 2. - Effectuer l’addition de
a
etb
, commenter le résultat. - Effectuer l’addition suivante :
x+a
; commenter le résultat, puis regarder le résultat dea+x
. - Multiplier le vecteur par le scalaire
c
que l’on fixera à 2. - Effectuer la multiplication de
a
etb
; commenter le résultat. - Effectier la multiplication suivante :
x*a
; commenter le résultats. - Récupérer les positions des multiples de 2 et les stocker dans un vecteur que l’on nommera
ind
, piuis conserver uniquement les multiples de 2 dex
dans un vecteur que l’on nommeramult_2
. - Afficher les éléments de
x
qui sont multiples de 3 et multiples de 2. - Afficher les éléments de
x
qui sont multiples de 3 ou multiples de 2. - Calculer la somme des éléments de
x
. - Remplacer le premier élément de
x
par un 4. - Remplacer le premier élément de
x
par la valeurNaN
, puis calculer la somme des éléments dex
. 18 Supprimer le vecteurx
.
Deuxième exercice
- Créer la matrice suivante : \(A = \begin{bmatrix} -3 & 5 & 6 \\ -1 & 2 & 2 \\ 1 & -1 & -1 \end{bmatrix}\).
- Afficher la dimension de
A
, son nombre de colonnes, son nombre de lignes et sa longueur. - Extraire la seconde colonne de
A
, puis la première ligne. 4.Extraire l’élément en troisième position à la première ligne. - Extraire la sous-matrice de dimension \(2\times 2\) du coin inférieur de
A
, c’est-à-dire \(\begin{bmatrix} 2 & 2 \\ -1 & -1 \end{bmatrix}\). - Calculer la somme des colonnes puis des lignes de A.
- Afficher la diagonale de
A
. - Rajouter le vecteur \(\begin{bmatrix} 1 & 2 & 3\end{bmatrix}^\top\) à droite de la matrice
A
et stocker le résultat dans un objet appeléB
. - Retirer le quatrième vecteur de
B
. - Retirer la première et la troisième ligne de
B
. - Ajouter le scalaire 10 à
A
. - Ajouter le vecteur \(\begin{bmatrix} 1 & 2 & 3\end{bmatrix}^\top\) à
A
. - Ajouter la matrice identité \(I_3\) à
A
. - Diviser tous les éléments de la matrice
A
par 2. - Multiplier la matrice
A
par le vecteur ligne \(\begin{bmatrix} 1 & 2 & 3\end{bmatrix}^\top\). - Afficher la transposée de
A
. - Effectuer le produit avec transposition \(A^\top A\).