Librairie: Numpy-Scipy-Matplotlib¶
En Python, il existe un très grand nombre de librairie pour toute sorte de tâche. La syntaxe pour importer une librairie est la suivant
import nom_du_module
Voici un exemple.
import math
Toutes les fonctions de la librairie math
sont maintenant disponibles, et pour utiliser ces fonctions on utilise le prefixe qui correspond au nom du module. Par exemple,
math.cos(math.pi)
-1.0
Vous remarquerez facilement que cette syntaxe n'est pas pratique, voir même lourde. Pour simplifier, on peut renommer la librairie lors de l'import de celle-ci. La syntaxe est la suivante.
import nom_du_module as nm
Voici un exemple.
import numpy as np
np.cos(np.pi)
-1.0
On peut aussi n'importer qu'une partie, ou qu'une fonction d'une librairie. La syntaxe est la suivante.
from nom_du_module import sous_partie
Voici un exemple.
from numpy import pi
Ce qui nous permet d'avoir une syntaxe plus agréable qu'au départ
np.cos(pi)
-1.0
On peut aussi faire
from numpy import cos, pi
cos(pi)
Enfin, on peut renommer une sous partie comme suit.
from nom_du_module import sous_partie as sp
Voici un exemple dans lequel on va extraire pyplot
de matplotlib
et qu'on va renommer plt
from matplotlib import pyplot as plt
Voici un exemple d'utilisation de la fonction plot de pyplot
x = range(10)
plt.plot(x, x, "o-")
[<matplotlib.lines.Line2D at 0x7f25688e4160>]
Nous nous concentrerons sur les librairies
- Numpy
- Scipy (linalg, integrate, stats,...)
- Matplotlib (pyplot)
Scipy (Scientifique python)¶
Il s'agit d'une librairie contenant différents sous modules pour l'optimisation optimize
, l'integration numérique et les equations différentiells integrate
, l'algèbre linéaire linalg
, ou les statistiques stats
, etc...
Matplotlib (2007 John Hunter)¶
Il s'agit d'un module de visualisation, avec des possibilités très proche de celles de Matlab.
Numpy (2006 Travis Oliphant)¶
- Librairie de calcul scientifique.
- Implémente des objets de typs
ndarray
(n dimensional array) qui sont des tableaux multidimensionnels qu'on peut applelernumpy array
.
x = np.array([1, 2, 3, 4, 5, 6])
print(x)
[1 2 3 4 5 6]
type(x)
numpy.ndarray
- Ces tableaux permettent des opérations rapides.
Si on prend deux listes d'entier et qu'on veut faire leur somme, voici ce qu'il se passe.
x = [1, 2, 3, 4]
y = [5, 6, 7, 8]
x + y
[1, 2, 3, 4, 5, 6, 7, 8]
Elles sont concaténées, mais on n'a pas une somme terme à terme. Par contre, pour si ce sont des numpy array
on aura bien une somme terme à terme.
x = np.array([1, 2, 3, 4])
y = np.array([5, 6, 7, 8])
x + y
array([ 6, 8, 10, 12])
Une remarque importante cependant! Créons une matrice de la façon suivante.
M = np.arange(1, 5).reshape(2,2)
print(M)
np.arange(1, 5)
[[1 2] [3 4]]
array([1, 2, 3, 4])
Faisons maintenant
M1 = M
et modifions $M$
M[0,0] = 2
Mais on remarque que
M1[0,0]
2
$M1$ a été modifié! Si on ne souhaite pas modifier $M1$ dans une telle opération, il faut faire une copie de $M$.
M = np.arange(1,5).reshape(2,2)
M1 = M.copy()
M[0,0] = 2
M1[0,0]
1
- La vectorisation: Numpy est optimisé pour éviter l'usage des boucle
for
.
Voici une différence entre la fonction cos
de numpy et celui de la librairie math
.
math.cos(x)
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-11-5aa3f5169bb5> in <module> ----> 1 math.cos(x) TypeError: only size-1 arrays can be converted to Python scalars
On voit que le fonction de math
ne supporte pas comme argument une liste de nombre. Si on veut toutes les images des point de x
il faudrait faire une boucle for
. Par contre, avec le cos
de numpy, il n' y a aucun problème.
np.cos(x)
array([ 0.54030231, -0.41614684, -0.9899925 , -0.65364362])
Broadcasting: Numpy gère les différencees de tailles de tableau durant les opérations, mais attention ceci peut être dangereux! Voici les rêgles.
$\begin{pmatrix} a & b & c \\ d & e & f \end{pmatrix} + z = \begin{pmatrix} a & b & c \\ d & e & f \end{pmatrix} + \begin{pmatrix} z & z & z \\ z & z & z \end{pmatrix} = \begin{pmatrix} a+z & b+z & c+z \\ d+z & e+z & f+z \end{pmatrix}$
$\begin{pmatrix} a & b & c \\ d & e & f \end{pmatrix} + \begin{pmatrix} x & y & z \end{pmatrix} = \begin{pmatrix} a & b & c \\ d & e & f \end{pmatrix} + \begin{pmatrix} x & y & z \\ x & y & z \end{pmatrix} = \begin{pmatrix} a+x & b+y & c+z \\ d+x & e+y & f+z \end{pmatrix}$
$\begin{pmatrix} a & b & c \\ d & e & f \end{pmatrix} + \begin{pmatrix} y \\ z \end{pmatrix} = \begin{pmatrix} a & b & c \\ d & e & f \end{pmatrix} + \begin{pmatrix} y & y & y \\ z & z & z \end{pmatrix} = \begin{pmatrix} a+y & b+y & c+y \\ d+z & e+z & f+z \end{pmatrix}$
$\begin{pmatrix} a & b & c \end{pmatrix} + \begin{pmatrix} y \\ z \end{pmatrix} = \begin{pmatrix} a & b & c \\ a & b & c \end{pmatrix} + \begin{pmatrix} y & y & y \\ z & z & z \end{pmatrix} = \begin{pmatrix} a+y & b+y & c+y \\ a+z & b+z & c+z \end{pmatrix}$
Voici les exemples correspondant. On remarquera qu'une matrice est une sorte de liste de liste dont les sous lignes correspondent aux ligne de la matrice.
x = np.array([[1, 2, 3], [4, 5, 6]])
print(x)
[[1 2 3] [4 5 6]]
x + 5
array([[ 6, 7, 8], [ 9, 10, 11]])
y = np.array([7, 8, 9])
x + y
array([[ 8, 10, 12], [11, 13, 15]])
y = np.array([[8], [9]])
x + y
array([[ 9, 10, 11], [13, 14, 15]])
x = np.array([1, 2, 3])
x + y
array([[ 9, 10, 11], [10, 11, 12]])
- Fonction universelle: Ce sont des fonctions qui opèrent sur des tableaux éléments par éléments. On retrouve toutes les fonctions usuelles
cos
,sin
,sqrt
,exp
,log
,... Voici deux exemples moins triviaux.
x = np.array([1, 2, 3])
y = np.array([2, 4, 6])
np.divide(x, y)
array([0.5, 0.5, 0.5])
np.power(x,y)
array([ 1, 16, 729])
Numpy manipulations¶
Voici maintenant plus de détail sur la manipulation des tableaux numpy.
Création d'un ndarray à partir d'une liste¶
x = np.array([1, 2, 3, 4, 5, 6])
print(x.dtype) # indique le type des données dans le tableau
print(x.shape) # retourne un tuple donnant la taille du tableau
int64 (6,)
x.shape = (2,3) # redéfinie la taille de x
print(x)
[[1 2 3] [4 5 6]]
x2 = np.array([[1, 2, 3],[4, 5, 6]]) # pour obtenir la même matrice
print(x2)
[[1 2 3] [4 5 6]]
x = x.astype('complex') # modification du type des données
print(x.dtype)
print(x)
complex128 [[ 1.+0.j 2.+0.j 3.+0.j] [ 4.+0.j 5.+0.j 6.+0.j]]
Génération de tableau¶
np.ones(size) renvoie une matrice de 1, où size est un tuple décrivant la taille du tableau.
print( np.ones((3,2)) )
[[1. 1.] [1. 1.] [1. 1.]]
Si on veut juste une matrice ligne, size est juste un entier
print( np.ones(3) )
[1. 1. 1.]
Pour une matrice ou ligne de zéros
print( np.zeros((3,2)) )
[[ 0. 0.] [ 0. 0.] [ 0. 0.]]
print( np.zeros(3) )
[ 0. 0. 0.]
Pour la matrice identité de taille n (=3 ci-dessous)
print( np.eye(3) )
[[1. 0. 0.] [0. 1. 0.] [0. 0. 1.]]
Pour une matrice diagonale
print( np.diag([1,2,3]) )
[[1 0 0] [0 2 0] [0 0 3]]
On peut générer les coefficients d'une matrice à partir d'une fonction à l'aide de la fonction np.fromfunction
M = np.fromfunction(lambda i, j: (i-2)**2+(j-2)**2, (5,5))
print(M)
[[8. 5. 4. 5. 8.] [5. 2. 1. 2. 5.] [4. 1. 0. 1. 4.] [5. 2. 1. 2. 5.] [8. 5. 4. 5. 8.]]
Pour accéder aux éléments des tableaux on procède d'une manière similaire aux listes.
print(M[0,0])
8.0
print(M[-1,-1])
8.0
print(M[3,:])
[ 5. 2. 1. 2. 5.]
M[:,0]
array([8., 5., 4., 5., 8.])
print(M[::2,::2])
[[ 8. 4. 8.] [ 4. 0. 4.] [ 8. 4. 8.]]
print(M[2:5,2:5])
[[ 0. 1. 4.] [ 1. 2. 5.] [ 4. 5. 8.]]
print(M[0, [1,2,4]])
[ 5. 4. 8.]
On peut aussi appliquer ce qu'on appelle des masques.
print(M[M % 2 == 0])
[ 8. 4. 8. 2. 2. 4. 0. 4. 2. 2. 8. 4. 8.]
M % 2 == 0
array([[ True, False, True, False, True], [False, True, False, True, False], [ True, False, True, False, True], [False, True, False, True, False], [ True, False, True, False, True]])
Ici, on ne considère que les indices pour lesquelles les coefficents sont pairs, et on peut leurs réaffecter une nouvelle valeur.
M[M % 2 == 0] = 0
print(M)
[[ 0. 5. 0. 5. 0.] [ 5. 0. 1. 0. 5.] [ 0. 1. 0. 1. 0.] [ 5. 0. 1. 0. 5.] [ 0. 5. 0. 5. 0.]]
L'équivalent de range
est arange
print( np.arange(16) ) # vecteur d'élément de 0 à n par pas de 1
[ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15]
print( np.arange(0.1, 1, 0.2) ) # vecteur d'éléements de a à b par
# pas de p (jusqu'à b-p!): np.arange(a,b,p)
[0.1 0.3 0.5 0.7 0.9]
Par contre si on ne veut pas se donner le pas mais le nombre d'élément on utlise np.linspace(a,b,n)
, n étant le nombre d'éléments
print( np.linspace(0.1, 1, 12) )
[0.1 0.18181818 0.26363636 0.34545455 0.42727273 0.50909091 0.59090909 0.67272727 0.75454545 0.83636364 0.91818182 1. ]
a = np.linspace(0.1, 2, 12).reshape(3,4) # vecteur qu'on peut redimensionner
print(a)
[[0.1 0.27272727 0.44545455 0.61818182] [0.79090909 0.96363636 1.13636364 1.30909091] [1.48181818 1.65454545 1.82727273 2. ]]
print( np.tril(a,-1) ) # extraction la partie triangulaire inférieure de a
[[0. 0. 0. 0. ] [0.79090909 0. 0. 0. ] [1.48181818 1.65454545 0. 0. ]]
print( np.triu(a, 1) ) # de la même manière pour les triangulaires supérieures
[[ 0. 0.27272727 0.44545455 0.61818182] [ 0. 0. 1.13636364 1.30909091] [ 0. 0. 0. 2. ]]
print( np.triu(a, 2) )
[[ 0. 0. 0.44545455 0.61818182] [ 0. 0. 0. 1.30909091] [ 0. 0. 0. 0. ]]
Pour une matrice diagonale de même diagonale que a (on extrait la diagonale de a dans un premier temps).
print( np.diag(np.diag(a)) )
[[ 0.1 0. 0. ] [ 0. 0.96363636 0. ] [ 0. 0. 1.82727273]]
Operation sur les matrices¶
M = np.arange(16).reshape(4,4)
M.max() # retourne le max des coefficients de M
15
M.max(axis=0) # retourne le max de chaque colonne
array([12, 13, 14, 15])
M.max(axis=1) # retourne le max de chaque ligne
array([ 3, 7, 11, 15])
Rque: np.max(M)
, np.max(M, axis = ?)
marchent aussi! On a le même type de fonction pour le minimum en remplaçant max par min.
M.sum() # retourne la somme des coefficients de M
120
M.sum(axis=0) # retourne la somme de chaque colonne
array([24, 28, 32, 36])
M.sum(axis=1) # retourne la somme de chaque ligne
array([ 6, 22, 38, 54])
Rque: np.sum(M)
, np.sum(M, axis = ?)
marchent aussi!
M1 = np.arange(1,5).reshape(2,2)
M2 = np.arange(1,5).reshape(2,2)
print(M1 + M2)
[[2 4] [6 8]]
print(2*M1)
[[2 4] [6 8]]
print(M1 * M2) # produit terme à terme
[[ 1 4] [ 9 16]]
print(M1**2) # carré terme à terme
[[ 1 4] [ 9 16]]
np.concatenate((M1,M2), axis = 1) # concatenation
array([[1, 2, 1, 2], [3, 4, 3, 4]])
np.concatenate((M1,M2), axis = 0)
array([[1, 2], [3, 4], [1, 2], [3, 4]])
x = np.arange(3)
y = 2*np.arange(3)
print(np.dot(x,y)) # produit scalaire de vecteurs
10
M = np.arange(6).reshape(2, 3)
x = np.ones((3, 1)) # vecteur de taille 3x1
print( np.dot(M, x) ) # produit de M1 par x ( M1.dot(x) marche aussi)
[[ 3.] [12.]]
# produit de matrice
print( np.dot(M1,M) ) # Attention au dimension des matrice
# Rque: M1.dot(M) marche aussi
[[ 6 9 12] [12 19 26]]
# transposée de M
print( np.transpose(M) ) # M.transpose() marche aussi
[[0 3] [1 4] [2 5]]
M.T
array([[0, 3], [1, 4], [2, 5]])
# trace de M1
print( np.trace(M) ) # M.trace() marche aussi
4
Quelques figures pour finir avec pyplot¶
w = np.linspace(-1, 1, 50)
plt.plot(w, np.sin(2*np.pi*w), label = 'fonction') # label sert pour la legende
plt.ylabel('fct $\sin(2\pi \omega)$')
plt.xlabel('argument $\omega$')
plt.title("tracer d'une fonction periodique")
plt.legend()
plt.show()
Pour des formules plus avancées il faut plutôt utiliser les commandes suivantes :
plt.rc('text', usetex = True)
w = np.linspace(-1, 1, 50)
plt.plot(w, np.sin(2*np.pi*w), label = 'fonction') # label sert pour la legende
plt.rc('text',usetex = True)
plt.ylabel(r'fct $\sin(2\pi \omega)$')
plt.xlabel('argument $\omega$')
plt.title("tracer d'une fonction periodique")
plt.legend()
plt.show()
Nombres aléatoires¶
Pour génerer des nombres aléatoires, on peut utiliser le sous module random
de numpy.
import numpy.random as npr
Voir https://docs.scipy.org/doc/numpy/reference/routines.random.html pour les différentes lois et possibilités du module.
La graine peut être fixé pour forcer des tirages identiques lors de l'élaboration du code. Par exemple, npr.seed(123)
.
matrice aléatoire de coefficients indépendants de loi uniforme sur [-1,1]¶
x = npr.uniform(-1, 1, (200, 2))
On peut représenter ces points tirés aléatoirement sur un graphique.
plt.scatter(x[:,0], x[:,1], s = 20, label = 'point')
plt.axis([-1.05, 1.05, -1.05, 1.05]); # défini les axes
plt.ylabel('$U_2$')
plt.xlabel('$U_1$')
plt.title('$(U_1,U_2)$')
plt.show()
On peut faire des histogrammes.
x = npr.randn(100000)
n_bins = 50 # nbre de classe de l'histogramme
plt.hist(x,n_bins, density=True, facecolor='green', label = 'loi N(0,1)')
plt.title('histogramme')
plt.ylabel('probabilite')
plt.xlabel('variable')
plt.legend()
plt.show()
ou aussi des figures avec des sous-figures.
plt.figure(1) # On décalre la figure
w = np.linspace(-1, 1, 50)
plt.subplot(121) # On déclare la première sous-figure
plt.plot(w, np.sin(2*np.pi*w),'b-', label = 'sin')
plt.plot(w, np.cos(2*np.pi*w),'g-',label = 'cos')
plt.ylabel('fct $\sin(2\pi \omega)$')
plt.xlabel('argument $\omega$')
plt.title("tracer d'une fonction periodique")
plt.legend()
plt.subplot(122) # On déclare la deuxième sous-figure
x = npr.uniform(-1, 1, (200, 2))
plt.scatter(x[:,0], x[:,1], s = 20)
plt.axis([-1.05, 1.05, -1.05, 1.05]);
plt.ylabel('$U_2$')
plt.xlabel('$U_1$')
plt.title('$(U_1,U_2)$')
plt.show()