Les fonctions de Numpy#
Vidéo: Création de tableaux#
Créer des tableaux Numpy#
De nombreuses fonctions de Numpy sont dédiées à la construction de tableaux multidimensionnels. La liste complète des fonctions pour la création de tableaux peut se trouver dans la documentation Numpy. Attention à bien choisir la documentation appropriée à votre version de Numpy, accessible avec :
# Importation du module Numpy
import numpy as np
print(np.__version__)
1.24.4
La fonction arrayInfo
#
Nous allons créer une fonction pour afficher les informations relatives aux tableaux Numpy, même si nous verrons plus tard la syntaxe de création d’une fonction personnelle.
def arrayInfo(array_name):
""" Prints out the content, shape, dimensions and data type of an array """
print("-----")
print(array_name)
print("shape:", array_name.shape)
print("number of dimensions:", array_name.ndim)
print("datatype:", array_name.dtype)
print("-----")
return
Nous pouvons alors utiliser cette fonction comme une fonction Python pour obtenir des informations sur un tableau :
# Création d'un tableau Numpy
A = np.array([[3, 5, 9],
[4, 6, -2]])
# Utilisation de la fonction arrayInfo
arrayInfo(A)
-----
[[ 3 5 9]
[ 4 6 -2]]
shape: (2, 3)
number of dimensions: 2
datatype: int64
-----
Uns et zeros#
Voici quelques fonctions utiles pour créer des tableaux préremplis :
fonction |
description |
---|---|
|
retourne un tableau de forme donnée |
|
retourne un tableau rempli de 1 de forme donnée |
|
retourne un tableau rempli de 0 de forme donnée |
Par exemple, créons un tableau A
avec 3 lignes et 4 colonnes rempli de 1 :
A = np.ones((3, 4))
arrayInfo(A)
-----
[[1. 1. 1. 1.]
[1. 1. 1. 1.]
[1. 1. 1. 1.]]
shape: (3, 4)
number of dimensions: 2
datatype: float64
-----
On rappelle que la forme du tableau (shape) s’écrit sous la forme d’un tuple (voir Le module Numpy). Ici le tuple définit le nombre d’éléments dans chacune des dimensions du tableau : 3 éléments dans la dimension 0 (lignes), et 4 éléments dans la dimension 1 (colonnes), c’est-à-dire un tableau avec 3 lignes et 4 colonnes.
On remarque que le type des éléments du tableau est par défaut float64
, c’est-à-dire des réels. Si nous voulons un type différent, il faut ajouter l’argument dtype
à la fonction :
A = np.ones((3, 4), dtype = 'int64')
arrayInfo(A)
-----
[[1 1 1 1]
[1 1 1 1]
[1 1 1 1]]
shape: (3, 4)
number of dimensions: 2
datatype: int64
-----
Maintenant, créons un tableau à une dimension avec 5 éléments tous égaux à zéro. Pour cela, il faut se souvenir comment écrire un tuple avec 1 seul élément :
A = np.zeros((5,))
arrayInfo(A)
-----
[0. 0. 0. 0. 0.]
shape: (5,)
number of dimensions: 1
datatype: float64
-----
La fonction empty()
permet de créer un tableau rapidement. Mais attention, ce tableau n’est pas vide, contrairement à ce que le nom de la fonction laisse entendre :
A = np.empty((3, 3))
arrayInfo(A)
-----
[[4.68322943e-310 0.00000000e+000 0.00000000e+000]
[0.00000000e+000 0.00000000e+000 0.00000000e+000]
[0.00000000e+000 0.00000000e+000 0.00000000e+000]]
shape: (3, 3)
number of dimensions: 2
datatype: float64
-----
On peut tester la vitesse d’exécution des différentes fonctions avec la commande %timeit
:
# %timeit np.zeros((1000, 1000))
# %timeit np.empty((1000, 1000))
Comme on ne sait jamais vraiment ce que la fonction empty()
met dans le tableau initialisé, il est presque toujours préférable d’utiliser zeros()
ou ones()
, pour être certain de ce qui est dans le tableau.
Les erreurs liées à des variables non itialisées ou mal initialisées sont fréquentes en programmation, et c’est donc une bonne habitude à prendre de toujours être certain que les variables sont correctement initialisées.
Exercice#
Créer un tableau
A
de dimension 1, contenant 7 éléments tous égaux à \(4.2\) avec la fonctionones()
. Afficher les attributs du tableau avec la fonctionarrayInfo()
Créer un tableau vide B avec la fonction
zeros()
, de même forme que A, sans écrire explicitement de tuple en argument de la fonction
Show code cell source
# 1
A = np.ones((7,)) * 4.2
arrayInfo(A)
# 2
B = np.zeros(A.shape)
arrayInfo(B)
-----
[4.2 4.2 4.2 4.2 4.2 4.2 4.2]
shape: (7,)
number of dimensions: 1
datatype: float64
-----
-----
[0. 0. 0. 0. 0. 0. 0.]
shape: (7,)
number of dimensions: 1
datatype: float64
-----
Intervalles et pas#
Voici quelques fonctions utiles pour créer des tableaux dans un intervalle donné :
fonction |
description |
---|---|
|
valeurs régulièrement espacées pour un pas donné |
|
valeurs régulièrement espacées pour un nombre d’éléments donné |
|
valeurs régulièrement espacées sur une échelle logarithmique pour un nombre d’éléments donné |
La fonction linspace()
est utile pour générer des tableaux avec des valeurs définies sur un intervalle donné. Par exemple, pour générer un tableau avec 15 valeurs dans l’intervalle [−4, 4]
:
A = np.linspace(-4., 4, 15)
arrayInfo(A)
-----
[-4. -3.42857143 -2.85714286 -2.28571429 -1.71428571 -1.14285714
-0.57142857 0. 0.57142857 1.14285714 1.71428571 2.28571429
2.85714286 3.42857143 4. ]
shape: (15,)
number of dimensions: 1
datatype: float64
-----
Les deux premiers arguments de la fonction sont les bornes inférieure et supérieure, et le troisième argument est le nombre d’éléments du tableau. Si le nombre de points est omis, la fonction linspace()
utilisera la valeur par défaut de 50 points, ce que l’on peut vérifier dans l’aide de python :
# help(np.linspace)
Il arrive souvent que l’on veuille créer un tableau avec non pas un nombre d’éléments donné à l’avance, mais un pas donné à l’avance. Le pas est l’intervalle entre 2 éléments. Si l’intervalle entre n’importe quels 2 éléments consécutifs reste le même, on parle alors de pas fixe ou de pas constant.
Voici une petite routine qui permet de créer un tableau d’éléments compris entre 2 bornes connues à l’avance et un pas fixe :
# Paramètres
start = -1.0 # borne inférieure
end = 2.0 # borne supérieure
step = 0.1 # pas
# Création du tableau
interval = end - start # intervalle
num_points = int(interval / step) + 1 # nombre d'éléments
g = np.linspace(start, end, num_points) # tableau
# Attributs du tableau
arrayInfo(g)
-----
[-1. -0.9 -0.8 -0.7 -0.6 -0.5 -0.4 -0.3 -0.2 -0.1 0. 0.1 0.2 0.3
0.4 0.5 0.6 0.7 0.8 0.9 1. 1.1 1.2 1.3 1.4 1.5 1.6 1.7
1.8 1.9 2. ]
shape: (31,)
number of dimensions: 1
datatype: float64
-----
Exercice#
Pourquoi dans la routine précédente le nombre de points est donné par int(interval / step) + 1
?
La fonction arange()
génère des valeurs dans l’intervalle semi-ouvert [début, fin[ avec un pas donné. Cependant, il est conseillé de ne pas l’utiliser avec un pas non entier, car le résultat n’est pas toujours cohérent avec la définition. Par exemple :
print(np.arange(7.8, 8.4, 0.05))
[7.8 7.85 7.9 7.95 8. 8.05 8.1 8.15 8.2 8.25 8.3 8.35 8.4 ]
inclut l’élément 8.4 au lieu de l’exclure.
Par défaut la fonction arange()
va générer des valeurs entières si tous les arguments d’entrée sont des nombres entiers. De plus, si le pas est omis, la fonction arange()
utilisera le pas par de défaut de 1.
On peut donc l’utiliser à la place de la fonction range()
pour générer un tableau Numpy d’entiers :
A = np.arange(-3, 5)
# est équivalent à :
B = np.array(list(range(-3, 5)))
arrayInfo(A)
arrayInfo(B)
-----
[-3 -2 -1 0 1 2 3 4]
shape: (8,)
number of dimensions: 1
datatype: int64
-----
-----
[-3 -2 -1 0 1 2 3 4]
shape: (8,)
number of dimensions: 1
datatype: int64
-----
Exercice#
En vous aidant de l’aide de la fonction logspace()
, créer le tableau Numpy contenant toutes les puissances de \(10\) depuis \(10^{-4}\) à \(10^{5}\), puis affichez les attributs du tableau avec arrayInfo.
Show code cell source
# help(np.logspace)
A = np.logspace(-4, 5, 10)
arrayInfo(A)
-----
[1.e-04 1.e-03 1.e-02 1.e-01 1.e+00 1.e+01 1.e+02 1.e+03 1.e+04 1.e+05]
shape: (10,)
number of dimensions: 1
datatype: float64
-----
Vidéo: Manipuler les tableaux#
Manipulation de tableau#
Voici quelques fonctions utiles pour manipuler les tableaux Numpy. La liste complète est dans la documentation Numpy.
fonction |
description |
---|---|
|
donne une forme différente au tableau sans changer ses éléments |
|
retourne une copie 1D du tableau |
|
transposée du tableau |
|
joindre plusieurs tableaux |
|
ajoute des valeurs à la fin du tableau |
|
trouve les éléments uniques du tableau |
|
inverse l’ordre des éléments |
Voici quelques exemples d’utilisation de ces fonctions :
# Tableau de forme (2, 4)
A = np.array([[2, 7, 9, 1],
[-3, 4, 0, 2]])
arrayInfo(A)
-----
[[ 2 7 9 1]
[-3 4 0 2]]
shape: (2, 4)
number of dimensions: 2
datatype: int64
-----
# Reformer en tableau de forme (4, 2)
B = np.reshape(A, (4, 2))
arrayInfo(B)
-----
[[ 2 7]
[ 9 1]
[-3 4]
[ 0 2]]
shape: (4, 2)
number of dimensions: 2
datatype: int64
-----
# Attention, on voit que reshape est différent de la transposée, que l'on obtient comme suit :
C = A.T
arrayInfo(C)
-----
[[ 2 -3]
[ 7 4]
[ 9 0]
[ 1 2]]
shape: (4, 2)
number of dimensions: 2
datatype: int64
-----
On peut joindre 2 tableaux suivant un axe donné, ici la première dimension, ou dimension 0 (lignes), avec la fonction append()
:
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6]])
D = np.append(A, B, axis = 0)
arrayInfo(D)
-----
[[1 2]
[3 4]
[5 6]]
shape: (3, 2)
number of dimensions: 2
datatype: int64
-----
Si on veut joindre plusieurs tableaux ensemble, il faut les concaténer avec la fonction concatenate()
:
C = np.array([[7, 8], [9, 10], [11, 12]])
D = np.concatenate((A, B, C), axis = 0)
arrayInfo(D)
-----
[[ 1 2]
[ 3 4]
[ 5 6]
[ 7 8]
[ 9 10]
[11 12]]
shape: (6, 2)
number of dimensions: 2
datatype: int64
-----
Un peu de tri#
Il peut être utile de trier un tableau Numpy. Reprenons les tableaux de la leçon précédente donnant les nombres d’habitants et les superficies des 8 villes les plus peuplées de France en 2017 :
noms = np.array(['Paris', 'Marseille', 'Lyon', 'Toulouse', 'Nice', 'Nantes', 'Montpellier', 'Strasbourg'])
nombre_habitants = np.array([2187526, 863310, 516092, 479553, 340017, 309346, 285121, 280966])
superficie = np.array([105.40, 240.62, 47.87, 118.30, 71.92, 65.19, 56.88, 78.26]) # km**2
Nous voyons que les tableaux sont triés suivant la donnée du nombre d’habitants, du plus grand au plus petit. On aimerait trier les données des villes suivant la donnée de la superficie en ordre décroissant. On peut utiliser les fonctions sort()
et flip()
:
superficie_sorted = np.sort(superficie) # Tri par défaut dans l'ordre croissant
superficie_sorted = np.flip(superficie_sorted) # Inverse l'ordre du tri
print(superficie_sorted)
[240.62 118.3 105.4 78.26 71.92 65.19 56.88 47.87]
Si on obtient bien un tableau trié dans le bon ordre pour les superficies, les tableaux contenant les nombres d’habitants et les noms de ville n’ont pas été triés, et on ne sait pas dans quel ordre les trier pour qu’ils correspondent au nouvel ordre du tableau donnant les superficies.
Pour résoudre ce problème, on va utiliser un masque d’indices grâce à la fonction argsort()
. Cette fonction retourne non pas le tableau trié, mais le tableau d’indices qui permet de trier le tableau. On peut alors utiliser ce masque d’indices en indice pour trier les autres tableaux :
mask = np.argsort(superficie) # Retourne le masque d'indices pour trier le tableau dans l'ordre croissant
mask = np.flip(mask) # Inverse l'ordre du masque pour obtenir un ordre décroissant
# Application du masque sur les 3 tableaux
noms_sorted = noms[mask]
nombre_habitants_sorted = nombre_habitants[mask]
superficie_sorted = superficie[mask]
# Affichage des tableaux triés
print(noms_sorted)
print(nombre_habitants_sorted)
print(superficie_sorted)
['Marseille' 'Toulouse' 'Paris' 'Strasbourg' 'Nice' 'Nantes' 'Montpellier'
'Lyon']
[ 863310 479553 2187526 280966 340017 309346 285121 516092]
[240.62 118.3 105.4 78.26 71.92 65.19 56.88 47.87]
Vidéo: format DateTime64 et fonctions maths#
Quelle est la date ?#
Afin de manipuler simplement des dates, Numpy a un type de données datetime64
. On peut alors utiliser les fonctions vues plus haut sur ce nouveau type de données.
Pour créer une date on utilise alors la fonction datetime()
:
date = np.datetime64('2021-09-21')
print("La date est :", date)
print("L'année est :", np.datetime64(date, 'Y'))
La date est : 2021-09-21
L'année est : 2021
On peut créer simplement des tableaux de dates avec la fonction arange()
:
dates = np.arange('2021-09', '2021-10', dtype = 'datetime64[D]')
print("Dates de septembre 2021 :\n", dates)
print("La date est en septembre :", date in dates)
Dates de septembre 2021 :
['2021-09-01' '2021-09-02' '2021-09-03' '2021-09-04' '2021-09-05'
'2021-09-06' '2021-09-07' '2021-09-08' '2021-09-09' '2021-09-10'
'2021-09-11' '2021-09-12' '2021-09-13' '2021-09-14' '2021-09-15'
'2021-09-16' '2021-09-17' '2021-09-18' '2021-09-19' '2021-09-20'
'2021-09-21' '2021-09-22' '2021-09-23' '2021-09-24' '2021-09-25'
'2021-09-26' '2021-09-27' '2021-09-28' '2021-09-29' '2021-09-30']
La date est en septembre : True
Ou encore calculer des durées :
duree = np.datetime64('2022-01-05') - np.datetime64('2021-09-21')
print("No. de jours :", duree)
print("No. de semaines :", np.timedelta64(duree, 'W'))
No. de jours : 106 days
No. de semaines : 15 weeks
Ou encore trier un tableau de dates :
a = np.array(['2018-01-19', '2017-05-06', '2021-11-25'], dtype = 'datetime64')
print("Dates triées :", np.sort(a))
Dates triées : ['2017-05-06' '2018-01-19' '2021-11-25']
Pour aller plus loin
Le type datetime64
de Numpy est similaire au type datetime
de Python. On peut trouver les références pour Numpy ici, et pour Python ici.
Les fonctions mathématiques#
La force de Numpy est d’avoir de nombreuses fonctions mathématiques prédéfinies que l’on peut utiliser avec comme argument un tableau Numpy. La plupart de ces fonctions sont vectorisées, c’est-à-dire qu’elles fonctionnent avec des tableaux multidimensionnels, de la même manière que lorsque l’on a utilisé les opérateurs arithmétiques.
Voici une liste non exhaustive de fonctions classées par thème. La liste complète est dans l’aide de Numpy.
fonctions |
Numpy |
---|---|
Trigonométrique |
|
Somme, produit |
|
Exponentielle et logarithme |
|
Autres |
|
Ces fonctions appartiennent au module Numpy, il ne faut donc pas oublier d’écrire np.func()
pour les appeler.
Exercice#
Un oscillateur amorti en régime libre à une dimension, lorsque le taux d’amortissement \(\xi\) est faible, se déplace suivant l’équation
avec \(x\) la position, \(t\) le temps, et \(\omega_d=\omega_0\sqrt{1-\xi^2}\). Vous prendrez comme valeurs : \(C=1~\mathrm{m}\), \(\xi=0.1\), \(\omega_0=1~\mathrm{s}^{-1}\) et \(\phi=0.2~\mathrm{rad}\).
Créer le tableau Numpy
t
contenant 50 valeurs de \(t\) entre 0 et 10.Calculer alors le tableau Numpy
x
contenant les valeurs de \(x\) pour les valeurs correspondantes du tableaut
, grâce à une unique expressionAfficher le tableau des positions
Show code cell source
# Paramètres
C = 1 # m
xi = 0.1 # sans unités
w0 = 1 # s**-1
phi = 0.2 # radians
# Tableau des temps
t = np.linspace(0, 10, 50) # s
# Tableau correspondant des positions
x = C * np.exp(-xi * w0 * t) * np.sin(w0 * np.sqrt(1 - xi ** 2) * t + phi)
# Affichage des positions
print(x)
[ 0.19866933 0.38431009 0.54689659 0.6807386 0.78154248 0.84652994
0.87449045 0.86576775 0.82218372 0.74690515 0.64426118 0.51952075
0.37864069 0.227996 0.07410384 -0.07664723 -0.21825188 -0.34531696
-0.45325632 -0.53844506 -0.59832852 -0.63148334 -0.63763015 -0.61759912
-0.57325189 -0.50736454 -0.42347814 -0.32572417 -0.21863285 -0.10693294
0.00464846 0.11157817 0.20969347 0.29535659 0.3655817 0.41813022
0.45157202 0.46531119 0.45957698 0.43538141 0.39444687 0.3391076
0.27219031 0.19687956 0.11657387 0.03473899 -0.04523576 -0.12017224
-0.18722434 -0.24398044]