IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Programmation Python pour les scientifiques

Utilisation de modules sous Python - Cours avec exercices corrigés


précédentsommairesuivant

II. NumPy et matplotlib

II-A. Modules scientifiques

Il existe de nombreux modules scientifiques sous Python :

  • Image non disponibleNumPy : puissant outil pour créer, manipuler, et appliquer de nombreuses opérations sur des tableaux de nombres (matrices). Stable et bien documenté ;
  • Image non disponibleSciPy : fonctions mathématiques puissantes s'appliquant aux tableaux générés par NumPy. C'est la boîte à outil numérique pour les tableaux NumPy. Elle contient des opérations spécifiques (algèbre linéaire, statistique…) de manipulation de tableaux, de plus haut niveau que celles de NumPy ;
  • Image non disponiblematplotlib : permet le tracé de graphes de fonctions.

Nous allons voir de plus près les modules NumPy et matplotlib.

II-B. Le module NumPy

Le module NumPy permet de créer, de manipuler, des tableaux de nombres, ou matrices, et de leur appliquer des opérations mathématiques courantes.

La fonction array() permet de créer un tableau, ou array, à partir d'un tableau Python c'est-à-dire d'une liste de listes de nombres (de même longueur) :

 
Sélectionnez
>>> import numpy as np
>>> A = np.array([[1,1,1],[0,1,1],[0,0,1]])
>>> A
 array([[1, 1, 1],
        [0, 1, 1],
        [0, 0, 1]])
>>> print A
[[1 1 1]
 [0 1 1]
 [0 0 1]]

La fonction arange() crée une matrice ligne de façon assez analogue à la façon dont range() crée une liste, à ceci près que les coefficients ne sont pas forcément entiers :

 
Sélectionnez
>>> v = np.arange(0, 1.5, 0.5)
>>> v
array([ 0., 0.5, 1. ])
>>> 2*v
array([ 0., 1., 2. ])
>>> -2*v + 10
array([ 10., 9., 8. ])

On peut appliquer sur les tableaux de nombreuses opérations arithmétiques, certaines étant comprises terme à terme.

On accède aux éléments d'un tableau comme en Python, grâce à un indice entre crochets :

 
Sélectionnez
>>> A[0], A[1]
(array([1, 1, 1]), array([0, 1, 1]))
>>> A[1][0]
0

On peut échantillonner (slicing) :

 
Sélectionnez
>>> A[0:1]
array([[1, 1, 1]])
>>> A[::-1]
array([[0, 0, 1],
       [0, 1, 1],
       [1, 1, 1]])

Le type d'une matrice s'obtient grâce à la fonction shape(), son nombre d'éléments grâce à size(). La fonction reshape() permet de changer la forme (=type) d'une matrice :

 
Sélectionnez
>>> L=np.arange(0,10)
>>> np.size(L)
10
>>> np.reshape(L,(2,5))
array([[0, 1, 2, 3, 4],
       [5, 6, 7, 8, 9]])
>>> L
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> M = np.reshape(L,(2,5)) ; np.shape(M)
(2, 5)

Le produit matriciel s'obtient à l'aide de la fonction dot(). Si le deuxième argument est une matrice ligne, dot() la traitera si besoin est comme une matrice colonne, ou vecteur, en la transposant. C'est en effet plus pratique de saisir v= np.arange(0,3) ou v=array([0, 1, 2]) que v=array([[0],[1],[2]]).

Exemple : avec kitxmlcodeinlinelatexdvpA= \begin{pmatrix}1 & 1 & 1\\ 0 & 1 & 1\\ 0 & 0 & 1\end{pmatrix}finkitxmlcodeinlinelatexdvp et kitxmlcodeinlinelatexdvpv=\begin{pmatrix}0 & 1 & 2\end{pmatrix}finkitxmlcodeinlinelatexdvp.

Le produit kitxmlcodeinlinelatexdvpA \times vfinkitxmlcodeinlinelatexdvp n'est pas défini ; le produit kitxmlcodeinlinelatexdvpv \times A \,=\begin{pmatrix}0 & 1 & 3\end{pmatrix}finkitxmlcodeinlinelatexdvp. Le produit kitxmlcodeinlinelatexdvpA \, \times ^t v \,= \begin{pmatrix}3\\ 3\\ 2\end{pmatrix}finkitxmlcodeinlinelatexdvp.

Voilà ce que dot() retourne :

 
Sélectionnez
>>> np.dot(A,v)
array([3, 3, 2])
>>> np.dot(v,A)
array([0, 1, 3])

On le voit, lorsque la multiplication est impossible, pour kitxmlcodeinlinelatexdvpA \times vfinkitxmlcodeinlinelatexdvp, la fonction effectue kitxmlcodeinlinelatexdvpv \, \times ^t Afinkitxmlcodeinlinelatexdvp, qui a retourné pour résultat kitxmlcodeinlinelatexdvp\begin{pmatrix}3 & 3 & 2\end{pmatrix}finkitxmlcodeinlinelatexdvp.

On pourra saisir les « vecteurs » sous forme de matrice ligne (leur transposée). Ce fonctionnement est commun aux logiciels de calcul sur des matrices (Matlab et Scilab).

Pour effectuer le produit scalaire de deux « vecteurs », utiliser la fonction vdot().

La fonction transpose() permet d'obtenir la transposée :

 
Sélectionnez
>>> np.transpose(A)
array([[1, 0, 0],
       [1, 1, 0],
       [1, 1, 1]])

La transposée d'un « vecteur » est encore un « vecteur ».

Attention, l'opération A ** 2 correspond à une élévation au carré terme à terme :

 
Sélectionnez
>>> A ** 2
array([[1 1 1]
       [0 1 1]
       [0 0 1]])
>>> (2*A) ** 2
array([[4 4 4]
       [0 4 4]
       [0 0 4]])

Pour élever A au carré, faire plutôt :

 
Sélectionnez
>>> np.dot(A,A)
array([[1, 2, 3],
       [0, 1, 2],
       [0, 0, 1]])

Pour élever une matrice carrée A à une puissance n :

 
Sélectionnez
>>> B = A
>>> for i in range(1,n):
        B = np.dot(A,B) # à la sortie de boucle B contient A^n

De même l'inversion A ** -1 se fait terme à terme. Elle produira ici une erreur (division par 0) alors même que la matrice A est inversible.

Certaines fonctions plus spécifiques sont disponibles dans un sous-module. Pour l'algèbre linéaire. C'est le sous-module linalg de NumPy. Toutes les fonctions de ce sous-module devront être saisies avec le préfixe np.linalg.

Pour l'inversion de matrice : utiliser la fonction inv() du sous-module linalg :

 
Sélectionnez
>> np.linalg.inv(A)
array([[ 1., -1., 0.],
       [ 0., 1., -1.],
       [ 0., 0., 1.]])

Le sous-module linalg contient aussi, entre autres :

  1. La fonction det() qui retourne le déterminant d'une matrice ;
  2. La fonction solve(A, b) qui résout le système linéaire de matrice A et de second membre b (vecteur ou ligne).

Exemple : résoudre le système linéaire :

kitxmlcodelatexdvp\left\{ \begin{array}{r c l} x-y+z &=& 1\\ -x+y+z &=& 1\\ 2x-y-z &=& 0 \end{array} \right.finkitxmlcodelatexdvp

Solution : cliquez sur l'icône Image non disponible pour dévoiler le code.

 
Cacher/Afficher le codeSélectionnez

array(liste)

Crée un tableau à partir d'une liste.

arange(a, b, k)

Crée un vecteur dont les coefficients sont les a+k.N entre a (inclus) et b (exclu).

linspace(a, b, n)

Crée un vecteur de n valeurs régulièrement espacées entre a et b (inclus).

zeros(p)

Crée un tableau de taille p rempli de zéros.

zeros((p, q))

Crée un tableau de taille (p, q) rempli de zéros.

ones(p)

Crée un tableau de taille p rempli de uns.

ones((p, q))

Crée un tableau de taille (p, q) rempli de uns.

shape()

Pour obtenir la taille d'un tableau (= type d'une matrice).

size()

Pour obtenir le nombre d'éléments d'un tableau.

reshape()

Pour redimensionner un tableau.

dot()

Pour effectuer un produit matriciel de deux matrices.

vdot()

Pour effectuer un produit scalaire de deux « vecteurs ».

transpose()

Pour transposer une matrice.

rank()

Rang d'une matrice.

mean()

Valeur moyenne d'un tableau.

odeint()

Pour intégrer une équation différentielle.

linalg :

 

inv()

Inversion d'une matrice.

det()

Déterminant d'une matrice.

solve(A, b)

Résolution du système linéaire Ax=b.

NumPy contient aussi constantes et fonctions mathématiques usuelles.

II-C. Le module matplotlib

Pour le simple tracé de courbes, nous n'utiliserons que le sous-module pyplot importé, avec alias, à l'aide de la commande :

 
Sélectionnez
>>> import matplotlib.pyplot as pp

Voir la documentation Matplotlib.

● Les fonctions essentielles de pyplot sont :

  • plot() pour le tracé de points, de courbes ;
  • show() pour afficher le graphique créé.

● Utiliser plot() avec :

  • en premier argument la liste des abscisses ;
  • en deuxième argument la liste des ordonnées ;
  • en troisième argument (optionnel) le motif des points :

    • '.' pour un petit point,
    • 'o' pour un gros point,
    • '+' pour une croix,
    • '*' pour une étoile,
    • '-' points reliés par des segments,
    • '--' points reliés par des segments en pointillés,
    • '-o' gros points reliés par des segments (on peut combiner les options),
    • 'b', 'r', 'g', 'y' pour de la couleur (bleu, rouge, vert, jaune, etc.).

Voir la documentation pyplot.

Exemple : pour le tracé d'un nuage de points, le code saisi en ligne de commande suivant

 
Sélectionnez
>>> import matplotlib.pyplot as pp
>>> abs = [0, 1, 2, 3, 4, 5]
>>> ord = [0, 1, 1.5, 1, 2.5, 2]
>>> pp.plot(abs, ord, 'o')
[<matplotlib.lines.Line2D object at 0x10c6610d0>]
>>> pp.show()

va produire un graphique (au format .png) :

Image non disponible

Exemple : pour le tracé d'une ligne brisée :

 
Sélectionnez
>>> import matplotlib.pyplot as pp
>>> abs = [n/2. for n in range(10)]
>>> ord = [n % 2 for n in range(10)]
>>> pp.plot(abs,ord,'-b')
[<matplotlib.lines.Line2D object at 0x10dd1fa10>]
>>> pp.show()
Image non disponible

Exemple : pour le tracé de courbes représentatives de fonctions réelles :

 
Sélectionnez
>>> import matplotlib.pyplot as pp
>>> import numpy as np # pour linspace() et les fonctions mathématiques
>>> X = np.linspace(0, 2*np.pi, 256) # X = 256 pts régulièrement espac#es
>>> Ycos = np.cos(X) # image directe de X par cos
>>> Ysin = np.sin(X) # image directe de X par sin
>>> pp.plot(X,Ycos,'b') # tracé de la courbe de cos en bleu
[<matplotlib.lines.Line2D object at 0x10d5e2b50>]
>>> pp.plot(X,Ysin,'r') # tracé de la courbe de sin en rouge
[<matplotlib.lines.Line2D object at 0x1073aad90>]
>>> pp.show()
Image non disponible

On améliore le tracé en remplissant quelques options avant de le sauvegarder (au format .png dans le répertoire utilisateur).

 
Sélectionnez
>>> pp.plot(X, Ycos, 'b', X, Ysin, 'r') # Tracé simultané des deux courbes
>>> pp.grid(True) # Affiche la grille
>>> pp.legend(('cos','sin'), 'upper right', shadow = True) # Légende
>>> pp.xlabel('axe des x') # Label de l'axe des abscisses
>>> pp.ylabel('axe des y') # Label de l'axe des ordonnées
>>> pp.title('Fonctions cosinus et sinus') # Titre
>>> pp.savefig('ExempleTrace') # sauvegarde du fichier ExempleTrace.png
>>> pp.show()
Image non disponible

On peut tout aussi bien tracer des courbes paramétrées :

 
Sélectionnez
>>> T = np.linspace(0,2*np.pi,256) # paramètre t
>>> X = [ t * np.cos(t) for t in T ] # x(t) = t.cos(t)
>>> Y = [ t * np.sin(t) for t in T ] # y(t) = t.sin(t)
>>> pp.plot(X,Y,'b') # Tracé de la courbe paramétrée {(x(t),y(t))}
[<matplotlib.lines.Line2D object at 0x10c044ed0>]
>>> pp.show()
Image non disponible

Exemple : tracé du cercle unitaire :

 
Sélectionnez
>>> T = np.linspace(0,2*np.pi,256) # paramètre t
>>> X = np.cos(T) # x(t) = cos(t)
>>> Y = np.sin(T) # y(t) = sin(t)
>>> pp.plot(X,Y,'b') # Tracé de la courbe paramétrée {(x(t),y(t))}
>>> pp.axis('equal') # Pour que le repère soit orthonormé
>>> pp.title('Le cercle unitaire')
>>> pp.show()
Image non disponible

II-C-1. Illustration : approximation de pi

Encore une approximation de kitxmlcodeinlinelatexdvp\pifinkitxmlcodeinlinelatexdvp par une méthode de type Monte-Carlo, mais avec illustration graphique.

On tire au sort N points dans le domaine carré [−1, 1] × [−1, 1] selon une loi uniforme. La probabilité pour un point d'être choisi dans le disque unitaire est égale au quotient de l'aire du disque unitaire par l'aire du domaine carré, soit : kitxmlcodeinlinelatexdvp\dfrac{\pi}{4}finkitxmlcodeinlinelatexdvp

Ainsi d'après le théorème des grands nombres, si l'on tire un grand nombre de points, c'est-à-dire si N est suffisamment grand, la proportion des points tirés se trouvant dans le disque unitaire, avec kitxmlcodeinlinelatexdvpx^2+y^2 \leq 1finkitxmlcodeinlinelatexdvp, est presque sûrement proche de kitxmlcodeinlinelatexdvp\pi / 4finkitxmlcodeinlinelatexdvp.

 
Sélectionnez
import matplotlib.pyplot as pp # pyplot
import numpy as np # numpy
import random as rand # random

def monpi(N):
    X = [rand.uniform(-1,1) for i in range(N)] # choix aléatoire
    Y = [rand.uniform(-1,1) for i in range(N)]
    oui = non = 0 # Calcul de la proportion dans le disque
    for i in range(N):
        if X[i]**2 + Y[i]**2 <= 1:
            oui += 1
        else:
            non += 1
    print 'approximation de pi trouvée :' # impression du résultat
    print 4 * oui / float(oui+non)
    print np.pi
    # Tracé du graphique
    pp.plot([-1,1,1,-1,-1],[-1,-1,1,1,-1], 'b-') # tracé du carré
    T = np.linspace(0,2*np.pi,256)
    Xdisk = np.cos(T)
    Ydisk = np.sin(T)
    pp.plot(Xdisk,Ydisk,'b') # tracé du disque
    for i in range(N): # tracé du nuage de points
        if X[i]**2 + Y[i]**2 <= 1:
            pp.plot([X[i]],[Y[i]], 'g+') # vert si dedans
        else:
            pp.plot([X[i]],[Y[i]], 'r+') # rouge si dehors
    pp.axis('equal')
    pp.show()
 
Sélectionnez
>>> monpi(10000)
approximation de pi trouvée :
3.152
3.14159265359
Image non disponible

précédentsommairesuivant

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2015 Jean-Philippe PREAUX. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.