Le module NumPy#
Vidéo: Introduction#
Le tableau NumPy#
L’objet de base du module NumPy est un tableau à \(N\) dimensions (ndarray), que l’on appelera simplement tableau par la suite. Le plus simple pour créer un tableau est de convertir une liste en tableau. Pour cela, il faut utiliser la fonction array()
du module NumPy :
# Import du module NumPy avec un alias np
import numpy as np
# Création de la liste
ma_liste = [2.2, 6.1, 9.6, 1.3, 56.8, 8.0]
# Création du tableau NumPy
mon_tableau = np.array(ma_liste)
# Affichage du tableau et de son type
print(mon_tableau)
print(type(mon_tableau))
[ 2.2 6.1 9.6 1.3 56.8 8. ]
<class 'numpy.ndarray'>
Nous avons une nouvelle classe (ou type d’objet, c’est équivalent) : le numpy.ndarray
, ou tableau NumPy. Comme toute classe, il a des fonctions (appelées « méthodes ») et des opérateurs associés.
En Python, un objet a des attributs (des variables internes) auxquels on peut accéder en écrivant le nom de l’objet, suivi d’un point et du nom de l’attribut. Voici la liste des attributs d’un tableau NumPy :
attribut |
description |
---|---|
t.ndim |
nombre de dimensions |
t.shape |
taille du tableau dans chaque dimension |
t.size |
nombre total d’éléments |
t.dtype |
type des éléments du tableau |
Regardons quelques attributs de mon_tableau
:
# Attribut nombre de dimensions (ndim)
mon_tableau.ndim
1
# Attribut taille (size)
mon_tableau.size
6
# Attribut forme (shape) -> résultat sous la forme d'un tuple
mon_tableau.shape
(6,)
tuple
Un tuple est un type de données séquentiel comme les listes. Cependant, alors que les listes sont muables (modifiables), les tuples sont immuables (non modifiables). On peut créer un tuple comme une liste, mais en utilisant une paire de parenthèses plutôt que des crochets, par exemple a = (2, 4, 3)
. Pour différencier un tuple à un élément d’une simple paire de parenthèses, on ajoute une virgule après le chiffre, par exemple a = (2,)
.
# Attribut type des éléments (dtype)
mon_tableau.dtype
dtype('float64')
dtype
Numpy contient un nombre de types numériques beaucoup plus important que les types natifs de Python. De plus, il est possible de créer facilement de nouveaux types de données structurées. C’est pourquoi NumPy est adpaté au calcul scientifique. Le type par défaut d’un réel lorsque l’on crée un tableau est float64
. Ce type est équivalent (en précision) au type float
natif de Python. 64 bits correspond à la place que prend un scalaire en mémoire. On peut trouver une liste des types natifs de NumPy.
Exercice#
La liste suivante contient le nombre d’habitants des 8 villes de France les plus peuplées : Paris, Marseille, Lyon, Toulouse, Nice, Nantes, Strasbourg et Montpellier (chiffres INSEE 2012)
nombre_habitants = [2240621, 852516, 496343, 453317, 343629, 291604, 274394, 268456]
Importer le module
numpy
sans alias.Créer un tableau NumPy
np_nombre_habitants
à partir de la listenombre_habitants
.Afficher le tableau créé et son attribut dtype.
Show code cell source
# Import du module NumPy
import numpy
# Création du tableau NumPy
np_nombre_habitants = numpy.array(nombre_habitants)
# Afficher le tableau et son attribut dtype
print(np_nombre_habitants)
print(np_nombre_habitants.dtype)
[2240621 852516 496343 453317 343629 291604 274394 268456]
int64
Opérations sur les tableaux#
Un grand intérêt des tableaux NumPy par rapport aux listes Python est la possibilité de les utiliser dans des expressions avec des opérateurs arithmétiques.
Les opérateurs arithmétiques que l’on a vus pour les types scalaires en Python (addition, soustraction, multiplication, etc) s’appliquent terme à terme sur les tableaux.
Par exemple, si on multiplie un tableau par un scalaire, chaque élément du tableau est multiplié :
# Création du tableau
mon_tableau = np.array([2.2, 6.0, 9.6])
# Multiplication par un scalaire
print(0.5 * mon_tableau)
[1.1 3. 4.8]
On peut aussi utiliser des opérateurs arithmétiques dans des expressions avec des tableaux de même forme. Les opérations sont alors effectuées terme à terme : le 1er élément du 1er tableau avec le 1er élément du 2ème tableau, etc.
# Création de 2 tableaux
A = np.array([0, 5, 3])
B = np.array([2, 5, 1])
# Addition terme à terme
print(A + B)
[ 2 10 4]
On peut former des expressions avec des tableaux de types numériques différents. Le résultat correspond alors au type le plus général ou le plus précis (propriété appelée upcasting).
Par exemple, si on multiplie un tableau d’entiers avec un tableau de réels :
# Création d'un tableau de réels
A = np.array([0.0, 5.0, 3.0], dtype = 'float64')
# Création d'un tableau d'entiers
B = np.array([2, 5, 1], dtype = 'int64')
# Multiplication terme à terme
C = A * B
# Type des éléments du tableau résultant
print(C.dtype)
float64
Exercice#
Reprenons le tableau np_nombre_habitants
, donnant le nombre d’habitants des 8 villes de France les plus peuplées (Paris, Marseille, Lyon, Toulouse, Nice, Nantes, Strasbourg et Montpellier). On définit un tableau donnant la superficie de ces mêmes villes (en \(\mathrm{km}^2\)), dans le même ordre :
np_superficie = np.array([105.40, 240.62, 47.87, 118.30, 71.92, 65.19, 78.26, 56.88]) # km**2
Calculer la densité de population de chaque ville en nombre d’habitants par \(\mathrm{km}^2\). Affecter le résultat à une variable
np_densite
et afficher le résultat. Note : une seule expression sur une seule ligne est nécessaire pour effectuer le calcul.Quel est le type des éléments du tableau
np_densité
(attribut dtype) ?
Show code cell source
# Calcul de la densité de population (hab/km**2)
np_densité = np_nombre_habitants / np_superficie
# Afficher le résultat
print(np_densité)
# Attribut dtype du résultat
print(np_densité.dtype)
[21258.26375712 3542.99725709 10368.56068519 3831.92730347
4777.93381535 4473.14005216 3506.18451316 4719.69057665]
float64
Indexation et tranche#
Comme pour les listes, on peut utiliser les opérateurs indexation []
et tranche [m:n]
avec les tableaux Numpy.
Rappelons les règles d’indexation :
toute expression entière peut être utilisée comme indice
si un indice a une valeur négative, il compte en sens inverse, à partir de la fin de la liste
si vous essayez de lire ou d’écrire un élément qui n’existe pas, vous obtenez une erreur
# Création du tableau
A = np.array([4, 6, 1, 23, 3, 8, 9])
# Sélection de l'élément d'indice 3
print(A[3])
23
Attention
Comme pour les listes, le premier élément de la liste est numéroté avec l’indice 0
, le deuxième élément avec l’indice 1
, et ainsi de suite.
# Sélection d'une tranche du tableau
tranche = A[2:5]
# Affichage
print(tranche)
[ 1 23 3]
Attention
Comme pour les listes, l’élément de fin de la tranche est exclu.
Avec l’opérateur tranche, on peut décider de sauter des éléments, en écrivant [m:n:step]
. Par exemple, si on ne veut prendre qu’un élément sur deux :
# Création du tableau
A = np.array([4, 6, 1, 23, 3, 8, 9])
# Sélection d'un élément sur deux
tranche = A[0:7:2]
# Affichage
print(tranche)
[4 1 3 9]
Ou de manière équivalente :
# Sélection d'un élément sur deux
tranche = A[::2]
# Affichage
print(tranche)
[4 1 3 9]
En effet, si on ne spécifie pas de valeur pour m
et n
dans l’opérateur tranche [m:n:step]
, par défaut m
est l’indice du premier élément du tableau (0
), et n
est l’indice du dernier élément du tableau plus 1 (A.size
).
Vidéo: Tableaux à 2 dimensions#
Tableau à 2 dimensions#
Un tableau Numpy peut avoir autant de dimensions que l’on veut. Nous avons manipulé jusqu’ici des tableaux à une dimension, généralement utilisés pour contenir un type d’information. Nous avons introduit 2 tableaux Numpy :
np_nombre_habitants
qui contient le nombre d’habitant·es des 8 villes de France les plus peupléesnp_superficie
qui contient les superficies de ces 8 villes
Nous allons maintenant structurer ces informations en utilisant un tableau à 2 dimensions :
la première dimension (lignes) donne pour une ville donnée son nombre d’habitants et sa superficie
la deuxième dimension (colonnes) donne pour toutes les villes une information donnée (son nombre d’habitants ou sa superficie)
Nous allons créer le tableau Numpy à deux dimensions à partir d’une liste de listes :
# Création de liste contenant les informations : nombre d'habitant·es et superficie (km**2)
villes = [[2240621, 105.40], # Paris
[852516, 240.62], # Marseille
[496343, 47.87], # Lyon
[453317, 118.30], # Toulouse
[343629, 71.92], # Nice
[291604, 65.19], # Nantes
[274394, 78.26], # Strasbourg
[268456, 56.88]] # Montpellier
# Création du tableau Numpy à 2 dimensions
np_villes = np.array(villes)
Exercice#
Afficher les quatres attributs du tableau Numpy np_villes
: nombre de dimensions, taille du tableau dans chaque dimension, nombre total d’éléments, type des éléments du tableau.
Show code cell source
# Affichage des attributs du tableau
print(np_villes.ndim) # Nombre de dimensions
print(np_villes.shape) # Taille du tableau dans chaque dimension
print(np_villes.size) # Nombre total d'éléments
print(np_villes.dtype) # Type des éléments du tableau
2
(8, 2)
16
float64
Le tableau Numpy est de dimension 2, contient 8 lignes et 2 colonnes, pour 16 éléments.
Nous remarquons qu’il est de type float64
, alors que le nombre d’habitants est un entier. En effet, nous avons vu qu’un tableau Numpy ne peut contenir qu’un seul type de données. Par défaut, il transforme tous les nombres en réel float64
, selon le principe de l’upcasting vu plus haut.
Indexation et tranche 2D#
Les opérateurs d’indexation et de tranche s’utilisent de la même façon que pour un tableau à une dimension, mais il faut les spécifier pour chaque dimension :
le premier opérateur agit sur la première dimension (lignes)
le deuxième opérateur agit sur la deuxième dimension (colonnes)
L’avantage du tableau Numpy 2D sur une liste de listes est qu’il devient très facile d’extraire une information donnée pour toutes les villes. Par exemple :
# Extraire les superficies pour toutes les villes à partir du tableau Numpy 2D
print(np_villes[:, 1])
# Extraire les superficies pour toutes les villes à partir de la liste de listes
print([villes[0][1], villes[1][1], villes[2][1], villes[3][1], villes[4][1], villes[5][1], villes[6][1], villes[7][1]])
[105.4 240.62 47.87 118.3 71.92 65.19 78.26 56.88]
[105.4, 240.62, 47.87, 118.3, 71.92, 65.19, 78.26, 56.88]
Exercice#
À partir du tableau Numpy np_villes
:
Afficher le nombre d’habitants de la ville de Toulouse
Afficher les superficies des 4 dernières villes du tableau
Show code cell source
# Nombre d'habitants de la ville de Toulouse
print(np_villes[3, 0])
# Superficies des 4 dernières villes du tableau
print(np_villes[-4:, 1])
453317.0
[71.92 65.19 78.26 56.88]
Opérations sur tableaux 2D#
Comme pour les tableaux 1D, il est possible d’utiliser les tableaux 2D dans des expressions avec des opérateurs arithmétiques. Les opérateurs arithmétiques s’appliquent terme à terme sur des tableaux de même forme (shape).
Cependant, il est possible de former des expressions avec des tableaux de formes différentes. Il faut alors que le tableau 1D soit de la même taille que les tableaux à l’intérieur du tableau 2D (deuxième dimension, ou nombre de colonnes) :
A = np.array([[-1, 6, 3],
[4, 2, 8]])
B = np.array([3, 6, 0])
print('A * B = ', A * B)
print('A + B = ', A + B)
A * B = [[-3 36 0]
[12 12 0]]
A + B = [[ 2 12 3]
[ 7 8 8]]
Il est aussi possible de former des expressions à l’aide des opérateurs de tranche et d’indexation :
print(A[0, :] + B)
print(A[:, 0] + B[0])
[ 2 12 3]
[2 7]
Exercice#
Le tableau suivant donne l’évolution de la population entre 2012 et 2017 pour chacune des villes du tableau np_villes
utilisé précédemment :
evolution = [-53095, 10794, 19749, 26236, -3612, 17742, 6572, 16665]
Créer un tableau Numpy
np_evolution
à partir du tableauevolution
.Copier le tableau
np_villes
dans un tableaunp_villes_2017
avec la fonction Numpycopy()
(pour éviter l’aliasing, voir cours sur les listes).Additionner les valeurs du tableau
evolution
aux valeurs de la première colonne du tableaunp_villes_2017
, qui représentent le nombre d’habitant·es en 2012, afin d’obtenir un tableau avec les nombre d’habitant·es en 2017 en première colonneAfficher les populations des villes en 2012 et en 2017 : le classement des villes les plus peuplées de France a-t-il changé ?
Show code cell source
# Création du tableau Numpy
np_evolution = np.array(evolution)
# Copie du tableau en évitant l'aliasing
np_villes_2017 = np.copy(np_villes)
# Évolution de la population
np_villes_2017[:, 0] = np_villes_2017[:, 0] + np_evolution
# Comparaison des populations
print(np_villes[:, 0])
print(np_villes_2017[:, 0])
[2240621. 852516. 496343. 453317. 343629. 291604. 274394. 268456.]
[2187526. 863310. 516092. 479553. 340017. 309346. 280966. 285121.]
Vidéo: Statistiques#
Statistiques#
Il est très facile de faire des statistiques simples avec Numpy. Voyons quelques fonctions :
fonction |
description |
---|---|
|
médiane |
|
moyenne arithmétique |
|
somme des éléments du tableau |
|
écart-type |
|
matrice de correlation de Pearson |
La liste complète des fonctions et de leurs arguments optionnels est dans l’aide Numpy.
Exercice#
Comparer la moyenne et la médiane du nombre d’habitants pour les villes du tableau
np_villes
Calculer l’écart-type des superficies des villes du tableau
np_villes
Calculer le coefficient de corrélation entre le nombre d’habitants et la superficie. On rappele que :
avec
et \(\hat{\sigma}_X\) et \(\hat{\sigma}_Y\) sont les écart-types des variables \(X\) et \(Y\).
Show code cell source
# Moyenne du nombre d'habitants
mean_villes = np.mean(np_villes, axis = 0) # axis = 0 permet de faire la moyenne sur la 1ère dimension (lignes)
mean_hab = mean_villes[0]
# ou bien
mean_hab = np.mean(np_villes[:, 0])
# Médiane du nombre d'habitants
med_villes = np.median(np_villes, axis = 0) # axis = 0 permet de faire la médiane sur la 1ère dimension (lignes)
med_hab = med_villes[0]
# ou bien
med_hab = np.median(np_villes[:, 0])
# Écart-type des superficies
std_villes = np.std(np_villes, axis = 0)
std_sup = std_villes[1]
# ou bien
std_sup = np.std(np_villes[:, 1])
# Coefficient de corrélation entre le nombre d'habitants et la superficie
shape_ville = np_villes.shape
N = shape_ville[0] # Nombre de villes
mean_sup = mean_villes[1] # Moyenne de la superficie des villes
sigma_XY = 1 / N * (np_villes[:, 0] - mean_hab) * (np_villes[:, 1] - mean_sup)
cor_villes = np.sum(sigma_XY) / std_villes[0] / std_villes[1]
# Affichage des résultats
print("Moyenne du nombre d'habitants =", mean_hab)
print("Médiane du nombre d'habitants =", med_hab)
print('Ecart-type des superficies =', std_sup, "km**2")
print('Coefficient de corrélation =', cor_villes)
Moyenne du nombre d'habitants = 652610.0
Médiane du nombre d'habitants = 398473.0
Ecart-type des superficies = 58.26393781748706 km**2
Coefficient de corrélation = 0.29855441699187646