Logiciels scientifiques - HLMA310
Partie 1 : Python
Matrices et numpy
Joseph Salmon
[Link]
Université de Montpellier
1 / 46
Sommaire
Introduction et présentations du package numpy
Nombres (pseudo)-aléatoires
Importations/Exportations externes
Affectation et copie
2 / 46
Introduction
numpy ou comment se passer de Matlab :
§ faire du calcul numérique
§ faire du traitement sur des vecteurs, matrices et tenseurs
Ressources :
§ Science des données : Van der Plas (2016) (en anglais) et
dont le site internet associé est une mine de ressource :
[Link]
§ numpy, scipy : [Link]
3 / 46
Représentation de tenseur 1D
Cas vectoriel
4 / 46
Représentation de tenseur 2D
Cas matriciel
4 / 46
Représentation de tenseur 3D
Cas tensoriel
4 / 46
Forces et faiblesses
Points forts de numpy :
§ gratuit / open source
§ écrit en C et en Fortran (1) ùñ performances élevées pour
calculs vectorisés (calculs formulés comme des opérations sur
des vecteurs/matrices ; contraire de calcul par boucle (2) )
Points faibles de numpy :
§ plus verbeux que Matlab ou Julia (open source), dont la
syntaxe est plus proche des mathématiques
§ prise en main moins intuitive
(1) interfaçant BLAS/LAPACK
(2) [Link]
5 / 46
Chargement classique de numpy
Chargement standard de numpy :
>>> import numpy as np # importe numpy
>>> np.__version__ # vérifie la version utilisée
'1.14.3'
Rem: L’extension .np est courante et sera employée dans la suite
pour toute référence à numpy.
6 / 46
array/arrays
Dans la terminologie numpy : vecteurs, matrices et autres tenseurs
sont appelés arrays ( : tableaux).
Création d’array :
§ à partir de listes ou n-uplets Python
§ avec des fonctions dédiées, telles que arange, linspace, etc.
§ par chargement, à partir de fichiers externes
7 / 46
Création d’array à partir de liste
Vecteur : l’argument est une liste Python
>>> liste = [1, 3, 2, 4]
>>> vecteur = [Link](liste)
>>> print(vecteur)
[1 3 2 4]
Matrice : l’argument est une liste de liste
>>> matrice = [Link]([[1, 2], [3, 4]])
>>> print(matrice)
>>> print(matrice[0,0])
>>> print(matrice[0,1])
[[1 2]
[3 4]]
1
2
8 / 46
Création d’array : les tenseurs
Tenseur :
>>> tenseur = [Link]([[[1, 2], [3, 4]],
[[21, 21], [23, 34]]])
>>> print(tenseur)
[[[ 1 2]
[ 3 4]]
[[21 21]
[23 34]]]
9 / 46
array : type, taille, etc.
Vecteurs et matrices ont même type : ndarray
>>> type(vecteur), type(matrice), type(tenseur)
([Link], [Link], [Link])
Connaître les dimensions avec shape :
>>> [Link](vecteur), [Link], [Link]
((4,), (2, 2), (2, 2, 2))
Forcer les types de données dans un array :
>>> matrice_cpx = [Link]([[1, 2], [3, 4]], dtype=complex)
>>> matrice_cpx
array([[1.+0.j, 2.+0.j],
[3.+0.j, 4.+0.j]])
10 / 46
Plus sur les types
Autres types possibles reconnus par l’argument optionnel dtype :
§ int
§ float
§ complex
§ bool
Rem: possibilité de donner la précision (en bits) également avec
int64, int16, float128, complex128.
Plus sur ces types :
§ [Link]
[Link]
§ [Link]
[Link]
11 / 46
Création d’array par fonction de génération
arange : crée un array de nombres de type float ou int
>>> x = [Link](0, 10, 2) # start, stop, step
>>> x
array([0, 2, 4, 6, 8])
ou pour des flottants :
>>> y = [Link](-1, 1, 0.5)
>>> y
array([-1. , -0.5, 0. , 0.5])
Enfin pour connaitre le type :
>>> print([Link], [Link])
int64 float64
12 / 46
linspace, logspace
linspace :
>>> [Link](0, 5, 11) # début et fin sont inclus
array([0. , 0.5, 1. , 1.5, 2. , 2.5, 3. , 3.5, 4. , 4.5, 5. ])
logspace : similaire mais travaille en échelle logarithmique
>>> np.set_printoptions(precision=2) # for display
>>> [Link](0, 11, 10) # début et fin sont inclus
array([1.00e+00, 1.67e+01, 2.78e+02, 4.64e+03, 7.74e+04, 1.29e+06,
2.15e+07, 3.59e+08, 5.99e+09, 1.00e+11])
Rem: 0, renvoie à 100 ; 11 renvoie à 1011 , et 10 permet d’afficher
10 nombres entre ces deux bornes (en progression géométrique)
Utilité : pour afficher la vitesse de convergence d’algorithmes
d’optimisation, pour l’étude des prix en économie, ...
>>> 10**([Link](np.log10(10), np.log10(10**11), 10))
array([1.00e+00, 1.67e+01, 2.78e+02, 4.64e+03, 7.74e+04, 1.29e+06,
2.15e+07, 3.59e+08, 5.99e+09, 1.00e+11])
13 / 46
diag
>>> [Link]([1, 2, 3], k=0)
array([[1, 0, 0],
[0, 2, 0],
[0, 0, 3]])
Rem: diag peut extraire d’un array sa diagonale
>>> [Link]([Link]([1, 2, 3], k=0))
array([1, 2, 3])
sous/sur diagonale :
>>> [Link]([1, 2, 3], k=1)
array([[0, 1, 0, 0],
[0, 0, 2, 0],
[0, 0, 0, 3],
[0, 0, 0, 0]])
14 / 46
Transposition
Pour obtenir la transposition d’une matrice il suffit d’appliquer
l’argument .T à la matrice :
>>> [Link]([1, 2, 3], k=1).T
array([[0, 0, 0, 0],
[1, 0, 0, 0],
[0, 2, 0, 0],
[0, 0, 3, 0]])
Aussi la fonction transpose permet la même opération :
>>> [Link]([Link]([1, 2, 3], k=1))
array([[0, 0, 0, 0],
[1, 0, 0, 0],
[0, 2, 0, 0],
[0, 0, 3, 0]])
15 / 46
zeros
>>> [Link]((3,), dtype=int)
array([0, 0, 0])
ou encore :
>>> print([Link]((3, 2), dtype=float))
>>> print([Link]((1, 3), dtype=float))
>>> print([Link]((3, 1), dtype=float))
[[0. 0.]
[0. 0.]
[0. 0.]]
[[0. 0. 0.]]
[[0.]
[0.]
[0.]]
16 / 46
ones, full et eye
ones :
>>> [Link]((3,3))
array([[ 1., 1., 1.],
[ 1., 1., 1.],
[ 1., 1., 1.]])
full : remplit un array avec n’importe quel nombre
>>> [Link]((3, 5), 3.14)
array([[3.14, 3.14, 3.14, 3.14, 3.14],
[3.14, 3.14, 3.14, 3.14, 3.14],
[3.14, 3.14, 3.14, 3.14, 3.14]])
eye : matrice identité
>>> [Link](3)
array([[1., 0., 0.],
[0., 1., 0.],
[0., 0., 1.]])
17 / 46
Concaténation d’array
Concaténation verticale :
>>> A = [Link]([[0, 2],[ 3, 4]])
>>> B = [Link]([[1, 2],[ 5, 4]])
>>> [Link]((A,B)) # concaténation verticale
array([[0, 2],
[3, 4],
[1, 2],
[5, 4]])
Concaténation horizontale :
>>> [Link]((A,B)) # concaténation horizontale
array([[0, 2, 1, 2],
[3, 4, 5, 4]])
18 / 46
Fonctions sur les lignes / colonnes :
moyenne ( : mean)
Moyenne globale :
>>>[Link](A)
2.25
Moyenne des colonnes :
>>> [Link](B,axis=0) # moyenne en colonne
array([3., 3.])
Moyenne des lignes :
>>> [Link](B,axis=1) # moyenne en ligne
array([1.5, 4.5])
19 / 46
Fonctions sur les lignes / colonnes :
somme ( : sum)
Somme globale :
>>> [Link](A)
9
Somme des colonnes :
>>> [Link](A, axis=0) # somme en colonne
array([3, 6])
Somme des lignes :
>>> [Link](A, axis=1) # somme en ligne
array([2, 7])
20 / 46
Fonctions sur les lignes / colonnes :
Somme cumulée ( : cumsum)
Somme cumulée globale :
>>> [Link](A) # noter l'ordre en ligne
array([0, 2, 5, 9])
Somme cumulée des colonnes :
>>> [Link](A, axis=0) # somme cumulée en colonne
array([[0, 2],
[3, 6]])
Somme cumulée des lignes :
>>> [Link](A, axis=1) # somme cumulée en ligne
array([[0, 2],
[3, 7]])
Rem: idem pour prod et cumprod
21 / 46
Slicing
slicing : disponible pour les arrays (même syntaxe que pour les
listes et les chaînes de caractères, avec en plus la possibilité d’y
avoir accès pour chaque dimension) :
Accès en colonne :
>>> A[:,0] # accès première colonne
array([0, 3])
Accès en ligne :
>>>A[1,:] # accès deuxième ligne
array([3, 4])
22 / 46
Masques
Utilisation de masques booléens pour extraire certains éléments :
>>> print(A < 2)
>>> print(A[A < 2])
>>> A[A < 2] = 10
>>> print(A)
>>> A[0, 0] = 0
>>> print(A)
[[ True False]
[False False]]
[0]
[[10 2]
[3 4]]
[[0 2]
[3 4]]
23 / 46
Vectorisation des opérations
On peut appliquer les opérations usuelles sur un array : elles
seront alors appliquées terme à terme :
>>> 2**A
array([[ 1, 4],
[ 8, 16]])
>>> A**3
array([[ 0, 8],
[27, 64]])
>>> A + 1
array([[1, 3],
[4, 5]])
[Link](A) ‰ [Link](A)
terme à terme ‰ matriciel
24 / 46
Multiplication des matrices
Il y a plusieurs syntaxe pour faire le produit matriciel :
>>> A @ B
array([[10, 8],
[23, 22]])
>>> [Link](B)
array([[10, 8],
[23, 22]])
>>> [Link](A, B)
array([[10, 8],
[23, 22]])
25 / 46
Sommaire
Introduction et présentations du package numpy
Nombres (pseudo)-aléatoires
Importations/Exportations externes
Affectation et copie
26 / 46
Génération aléatoire
Utilité : en statistique et en probabilité
§ détails sur la manière dont Python gère la création de
nombres pseudo-aléatoires :
[Link]
§ détails sur le type d’algorithme utilisé (par défaut l’algorithme
de Mersenne Twister), on pourra se référer à
[Link]
en informatique, les opérations sont déterministes : l’aléatoire
n’existe pas, on parle de pseudo-aléatoire
27 / 46
Générateur de nombres aléatoires
“uniformes (3) ” entre 0. et 1.
Module pour générer des nombres aléatoires :
§ import random : le module aléatoire standard
§ [Link] : le module aléatoire de numpy
>>> [Link](5, 5) # aléatoire entre 0. et 1.
array([[0.2 , 0.63, 0.17, 0.11, 0.8 ],
[0.16, 0.16, 0.52, 0.03, 0.87],
[0.05, 0.41, 0.98, 0.36, 0.68],
[0.66, 0.45, 0.24, 1. , 0.66],
[0.14, 0.91, 0.13, 0.14, 0.13]])
En relançant la commande, la matrice créée est différente ! ! !
Rem: np.set_printoptions(precision=2) a restreint notre
affichage aux deux premiers chiffres après la virgule, d’où le “1.” !
(3) un rappel sur la loi uniforme est donné ici : [Link]
28 / 46
Graine ( : seed)
Pour la reproductibilité des résultats on peut souhaiter “geler”
l’aléa (e.g., pour des tests ou du débogage)
Graine ( : seed) : nombre utilisé pour initialiser un générateur
de nombres pseudo-aléatoires
Fonctionnement : fixer une graine permet de spécifier de manière
déterministe l’appel des opérations pseudo-aléatoires
>>> [Link](2018) # fixe la graine
>>> [Link](3, ) # tirage aléatoire
array([0.88234931, 0.10432774, 0.90700933])
Résultat : cette commande produit alors toujours la même sortie
29 / 46
Autres lois : exemple gaussien
Construction similaire pour d’autres lois : la plus connue étant la
loi gaussienne (ou loi normale), dont la fonction de densité est :
´ 2¯
exp ´ x2
ϕpxq “ ?
2π
On remplace alors [Link] par [Link]
§ Plus de détails sur cette loi :
[Link]
§ Pour d’autres lois classiques, cf. l’aide de numpy :
[Link]
[Link]
Rem: scipy : module d’outils scientifiques (statistiques,
optimisation, etc.) ; matplotlib : module d’affichage graphique
30 / 46
Affichage : histogramme et densité
from [Link] import norm # module loi normale
a = [Link](10000)
x = [Link](-4, 4, 100)
# Affichage d'un histogramme normalisé
fig = [Link](figsize=(8, 5))
hitogramme = [Link](a, bins=50, density=True)
# Oublier les détails matplotlib et Latex si besoin
[Link](x, [Link](x), linewidth=3, color='black',
label=r"$\frac{\exp\left(-\frac{x^2}{2}\right)}
{\sqrt{2\pi}}$")
[Link]("x")
[Link]("Proportion")
[Link]()
[Link]()
31 / 46
Histogramme et densité : cas gaussien
0.40 exp
(
x2
2 )
2
0.35
0.30
0.25
Proportion
0.20
0.15
0.10
0.05
0.00
4 2 0 2 4
x
32 / 46
Sommaire
Introduction et présentations du package numpy
Nombres (pseudo)-aléatoires
Importations/Exportations externes
Importations
Exportations
Affectation et copie
33 / 46
Import de fichiers en numpy
But : importer un fichier en ligne de commande (sans télécharger à
la main avec un navigateur)
Format visé (ici) : .csv ( : comma separated values).
>>> import os # interface système d'exploitation
>>> from download import download
Localiser le répertoire courant :
>>> !pwd # unix command "print working directory"
/home/jo/Documents/Mes_cours/Montpellier/HLMA310/Poly/codes
34 / 46
Sommaire
Introduction et présentations du package numpy
Nombres (pseudo)-aléatoires
Importations/Exportations externes
Importations
Exportations
Affectation et copie
35 / 46
Importation de fichiers (suite)
Url contenant le fichier de données :
>>> url = "[Link]
Téléchargement des fichiers :
>>> from download import download
>>> path_target = "./data_set.csv"
>>> download(url, path_target, replace=False)
Télécharge
file_sizes: 100% 30.0/30.0 [00:00<00:00, 37.0kB/s]
Downloading data from
[Link]
(30 bytes)
Successfully downloaded file to ./data_set.csv
36 / 46
Visualisation du fichier brut
Après téléchargement, le fichier brut est visualisable :
>>> !cat data_set.csv # commande pour visualiser
1,2,3,4,5
6,7,8,9,10
1,3,3,4,6
Rem: autres fonctions unix disponibles
§ cd : changer de dossier (change directory en anglais)
§ cp : copier des fichiers (copy en anglais)
§ ls : lister les fichiers à l’endroit courant (list en anglais)
§ man : avoir accès au manuel/aide (manual en anglais)
§ mkdir : créer un dossier (make directory en anglais)
§ mv : déplacer un fichier (move directory en anglais)
§ rm : supprimer un fichier (remove en anglais)
§ rmdir : supprimer un dossier (remove directory en anglais)
37 / 46
Import du fichier sous numpy
Import et lecture au format array de numpy :
>>> data_as_array = [Link]('data_set.csv',
delimiter=',')
>>> data_as_array
array([[ 1., 2., 3., 4., 5.],
[ 6., 7., 8., 9., 10.],
[ 1., 3., 3., 4., 6.]])
Rappel : csv signifie “comma-separated values” ( : valeurs
séparées par des virgules)
38 / 46
Sommaire
Introduction et présentations du package numpy
Nombres (pseudo)-aléatoires
Importations/Exportations externes
Importations
Exportations
Affectation et copie
39 / 46
Export sous forme de texte
Export standard [Link] ou en .txt :
[Link]("random_matrix.txt", data_as_array)
Vérification :
>>> !cat random_matrix.txt
1.000000000000000000e+00 2.000000000000000000e+00 ...
...
Solution alternative : ouvrir le fichier avec un éditeur de texte
(gedit, mousepad, etc.) pour vérifier son contenu (pas avec Word
ou LibreOffice)
40 / 46
Export sous format .npy
Sauvegarder ( : save) un array :
>>> [Link]("random_matrix.npy", data_as_array)
Charger ( : load) :
>>> data_as_array2 = [Link]("random_matrix.npy")
>>> data_as_array2
array([[ 1., 2., 3., 4., 5.],
[ 6., 7., 8., 9., 10.],
[ 1., 3., 3., 4., 6.]])
Rem: Pour effacer le fichier après usage (si besoin)
!rm data_set.csv
!rm random_matrix.txt
!rm random_matrix.npy
41 / 46
Sommaire
Introduction et présentations du package numpy
Nombres (pseudo)-aléatoires
Importations/Exportations externes
Affectation et copie
42 / 46
Affectation simple
>>> A = [Link]([[0, 2], [3, 4]])
>>> B = A
changer B va maintenant affecter A : l’affectation ne copie pas
le tableau, mais “l’adresse mémoire” du tableau d’origine
>>> B[0,0] = 10
>>> print(B)
>>> print(B is A) # les deux objets sont les mêmes
>>> print(A)
array([[10, 2],
[ 3, 4]])
True
array([[10 2]
[ 3 4]])
43 / 46
Copie profonde (deep copy)
Copie profonde ( : deep copy) de A dans B :
>>> B = [Link]()
Maintenant on peut observer le comportement différent :
>>> B[0, 0] = 111
>>> B
array([[111, 2],
[ 3, 4]])
A n’est alors plus modifié : on a créé une copie profonde de l’objet !
>>> A
array([[10, 2],
[ 3, 4]])
44 / 46
Tests entre array
Test (exact) terme à terme :
>>> A == B
array([[False, True],
[ True, True]])
Test approché :
>>> [Link](A, A+0.001)
False
Test approché à précision choisie :
>>> [Link](A, A+0.001, atol=0.01)
True
Rem: atol signifie absolute tolerance
45 / 46
Bibliographie I
§ VanderPlas, J. Python Data Science Handbook. O’Reilly
Media, 2016.
46 / 46