Vous êtes sur la page 1sur 97

Cours Python

Mirco Ciallella

filière Télécommunications à ENSEIRB-MATMECA

5-9 Décembre, 2022

1/97
Introduction
Pourquoi python ?

Un des 3 langage les plus utilisés en 2021.


Grand pannel d’utilisation, du simple script quotidien à la bibliothèque
complète
Langage à haut niveau d’abstraction, mais qui est peut facilement utiliser
des noyaux de calculs efficaces compilés en C ou C++.
Le développeur n’a pas (ou très peu) besoin de gérer la mémoire.
De plus en plus utilisé dans le monde scientifique, avec de nombreuses
bilbiothèques perfomantes, comme numpy, scipy, tensorflow. . .
Bonne portabilité.
Gratuit, libre et open-source (contrairement à Matlab).

2/97
Présentation de python
Python est un langage interprété

En tant que langage interprété, on peut lancer python dans un terminal et


taper les commandes les unes après les autres.

$ python3
Python 3.6.9 (default, Oct 8 2020, 12:12:24)
[GCC 8.4.0] on linux
Type "help" , "copyright" , "credits" or "license" for more information.
>>> print("Hello world" )
Hello world
>>> 3 + 5
8
>>>

Chaque ligne est évaluée et la sortie écrite automatiquement dans le terminal.


En pratique, on n’utilise ce mode uniquement pour des faire des
petits tests ou des petites opérations.
3/97
Présentation de python
Exemple de typage statique

Dans un langage à typage statique comme le C, une variable est définie avec
un type qui ne peut pas changer dans la portée courante.

int a = 3; // 'int' for integer


int b = 4;
float x = 32.5; // 'float' for a real number
printf("a = %d\n", a);
printf("b = %d\n", b);
printf("x = %f\n", x);

a = b; // OK, a and b are both int


printf("a = %d\n", a);

a = x; // OK, but a is an int, so it x is rounded


printf("a = %d\n", a);

x = a; // OK, a is converted to a float


printf("x = %f\n", x);

4/97
Présentation de python
Typage dynamique de python

On crée un fichier avec l’extention .py et on l’exécute avec python3 script.py


Dans un langage comme python, les variables ne sont pas déclarée
explicitement avec un type et une variable peut changer de type.

a = 3 # So a will be an integer
b = 4 # b too
x = 32.5 # x will be a float

a = b # OK
print("a =", a)

a = x # OK, now a is a float with value 32.5


print("a =", a)

x = b # OK, x is now an int with value 4


print("x =", x)

a = 12 # OK, now a is an int with value 12


print("a =", a)

5/97
Présentation de python
Typage dynamique de python

Cela permet une grande flexibilité mais peut aussi causer beaucoup de
problèmes !
On peut trouver le type d’une variable avec type() :

i = 2
print(type(i))
x = 3.0
print(type(x))
s = "Hello"
print(type(s))
s = i
print(type(s))

Output :

<class 'int' >


<class 'float' >
<class 'str' >
<class 'int' >

6/97
Présentation de python
Typage dynamique de python

On peut tester un type avec type(variable) directement ou


isinstance(variable, type) (plus robuste) :

a = 3

print(type(a) is int)
print(isinstance(a, int))

if type(a) is float:
print("a is float")

if isinstance(a, int):
print("a is int")

Output :

True
True
a is int

7/97
Les bases de la sytaxe en python
Indentation obligatoires entre les blocs

En C, on pourrait écrire de façon équivalente

int a = 1;
int b = 1;
int c;
if(a == 1){
if(b == 1)
{
c = 1;
}
else
{
c = 1000;
b = 1000;
}
}
printf("a = %d, b = %d, c = %d\n", a, b, c);

Output :

a = 1, b = 1, c = 1
8/97
Les bases de la sytaxe en python
Indentation obligatoires entre les blocs

et

int a = 1;
int b = 1;
int c;
if(a == 1){
if(b == 1){
c = 1;
}
else{
c = 1000;
b = 1000;
}
}
printf("a = %d, b = %d, c = %d\n", a, b, c);

Output :

a = 1, b = 1, c = 1

9/97
Les bases de la sytaxe en python
Indentation obligatoires entre les blocs

En python, contrairement à la majorité des langages, on n’est pas libre


d’indenter le code comme on veut.
En python, on commence un bloc (comme if ici) avec :

a = 1
b = 1
if a == 1:
if b == 1:
c = 1
else:
c = 1000
b = 1000
print("a =", a, "b =", b, "c =", c) # on peut mettre print("a"); print("b");

Output :

a = 1 b = 1 c = 1

10/97
Les bases de la sytaxe en python
Indentation obligatoires entre les blocs

Ce qui est bien différent de

a = 1
b = 1
if a == 1:
if b == 1:
c = 1
else:
c = 1000
b = 1000 # Go back in the first if and erase b
print("a =", a, "b =", b, "c =", c) # on peut mettre print("a"); print("b");

Output :

a = 1 b = 1000 c = 1

11/97
Les bases de la sytaxe en python
Commentaires

On peut commenter :
la fin d’une ligne à partir du symbole #
plusieurs lignes en les encadrant de ”””

print("1")
# print("2")
print("3")
"""
print("4")
print("5")
"""
print("6")

Output :

1
3
6

12/97
Types de base
Les chaı̂nes de caractères

name = "Tony Stark"


print(name)

Output :

Tony Stark

13/97
Types de base
Les chaı̂nes de caractères

Utiliser + pour concaténer les chaı̂nes de caractères

s1 = "Hello"
s2 = "every one"
final_string = s1 + " " + s2
print(final_string)

Output :

Hello every one

14/97
Types de base
Les chaı̂nes de caractères

Utiliser \n pour le saut de ligne

print("Tony" + "\n" + "Stark")


print("\nFrank\n\nCastle")

Output :

Tony
Stark

Frank

Castle

15/97
Types de base
Les chaı̂nes de caractères

Utiliser str() pour convertir en chaı̂ne de caractères

i = 32
print("La valeur est " + str(i))
# print("La valeur est " + i) # TypeError: must be str, not int

Output :

La valeur est 32

16/97
Types de base
Les chaı̂nes de caractères

Réciproquement, on peut convertir une chaı̂ne de caractères en entier.

trente_deux = "32"
v = int(trente_deux)
print(trente_deux)
print(v * 10)

Output :

32
320

17/97
Types de base
Les chaı̂nes de caractères

A noter qu’on peut utiliser ” ou ’ pour indifféremment délimiter les chaı̂nes de


caratères. En particulier, on peut mettre des ’ dans des chaı̂nes délimitées par
” et réciproquement.

print("A string with 'simple quote'")


print('A string with "double quote"')
print("A string with \"escaped double quote\"")

Output :

A string with 'simple quote'


A string with "double quote"
A string with "escaped double quote"

18/97
Types de base
Les chaı̂nes de caractères

Enfin, on peut tester si une sous-chaı̂ne est présente dans la chaı̂ne de


caractères avec le mot clé in.

print("eirb" in "enseirb-matmeca")
print("herbe" in "enseirb-matmeca")

Output :

True
False

19/97
Types de base
Formater les chaı̂nes de caractères

Quand on veut écrire les valeurs des variables, plutôt qu’ecrir ça

a = 2
b = 3
print("The sum of " + str(a) + " and " + str(b) + " equals " + str(a + b))

On peut déjà utiliser la syntaxe du print pour séparer les éléments

a = 2
b = 3
print("The sum of ", a, " and ", b, " equals ", a + b)

Output :

The sum of 2 and 3 equals 5

20/97
Types de base
Formater les chaı̂nes de caractères

On peut écrire la chaı̂ne directement en remplaçant les variables par des {},
puis en les insérant avec .format(var1, var2, . . .)

a = 2
b = 3
print("The sum of {} and {} equals {}".format(a, b, a + b))

Encore mieux, depuis python 3.6, on peut utiliser une syntaxe plus concise
appelée f-string

a = 2
b = 3
print(f"The sum of {a} and {b} equals {a + b}")

Output :

The sum of 2 and 3 equals 5

21/97
Types de base
Liste

Le type python ”liste” est une liste avec laquelle on peut accéder aux
éléments comme un tableau.
On déclare une liste avec [], et on sépare les éléments par ,.
On accède à l’élement numéro i avec l’opérateur [i]. Une liste de n
éléments est indexée de 0 à n − 1.

my_list = ['Earth', 'Water', 'Air', 'Fire']


print(my_list[0])
print(my_list[2])
print(type(my_list))

Output :

Earth
Air
<class 'list' >

22/97
Types de base
Liste

On peut utiliser des indices négatifs pour accéder aux éléments depuis la
fin
len donne la taille de la list
l’indice l[−k] est alors un raccourcis pour l[len(l) − k]
On peut rajouter un élément à la liste avec append
On peut supprimer un élément avec le mot clé del et l’indice de l’élément
à supprimer
On peut boucler sur les éléments d’une liste avec la boucle for et le mot
clé in

23/97
Types de base
Liste

my_list = ['Earth', 'Water', 'Air', 'Fire']


# Indexing with []
print(my_list[len(my_list) - 1]) # Last element
print(my_list[-1]) # Last element
print(my_list[-2]) # Element before the last one
# Append lists
print(my_list)
my_list.append("5th element")
print(my_list)
# Delete third element
del my_list[2]
print(my_list)
# For loop
for element in my_list:
print(element)

Fire
Fire
Air
['Earth' , 'Water' , 'Air' , 'Fire' ]
['Earth' , 'Water' , 'Air' , 'Fire' , '5th element' ]
['Earth' , 'Water' , 'Fire' , '5th element' ]
Earth
Water
Fire
5th element

24/97
Types de base
Dictionnaire

Les dictionnaires en python sont des tables, qui associent à une clé une valeur.
La syntaxe pour définir un dictionnaire est {}. On peut insérer un élément de
clé k ou y accèder avec [k].

my_dict = {} #Empty dictionary


my_dict[12] = "douze"
my_dict["Hello"] = "Goodbye"
my_dict["A list"] = [1, 2, 3]
print(my_dict)

Output :

{12: 'douze' , 'Hello' : 'Goodbye' , 'A list' : [1, 2, 3]}

25/97
Types de base
Dictionnaire

On peut aussi utiliser la syntaxe { key1 : value1, key2 : value2 }


directement. Pour supprimer un élément, on utiliser del avec la clé à
supprimer.

my_dict = { 12 : "douze",
"Hello" : "Goodbye",
"A list" : [1, 2, 3] }
print(my_dict)
del my_dict["Hello"]
print(my_dict)

Output :

{12: 'douze' , 'Hello' : 'Goodbye' , 'A list' : [1, 2, 3]}


{12: 'douze' , 'A list' : [1, 2, 3]}

26/97
Opérations de base de python
Boucles for avec range

range produit un itérateur d’entiers sur lesquelles boucler.


On donne le premier nombre de la liste, le premier nombre en dehors de la
liste et la valeur à incrémenter chaque fois.

# incrément positif
for i in range(3, 19, 4): # range(begin, end, step)
print(i)

# Le step peut ^
etre négatif
for i in range(10, 6, -1):
print(i)

3
7
11
15

10
9
8
7

27/97
Opérations de base de python
Boucles for avec range

On peut aussi écrire directement :


range(end), par défaut begin=0 et step=1
range(begin, end), par défault step=1
range est en fait un moyen de générer une liste

print(list(range(4)))
print(list(range(10, 15)))

Output :

[0, 1, 2, 3]
[10, 11, 12, 13, 14]

28/97
Opérations de base de python
Boucle while

La boucle ”tant que” se répète jusqu’à ce que la condition donnée soit fausse.

k = 0
while k < 3:
print(k)
k = k + 1 # Infinite loop if forgotten...

Output :

0
1
2

Il faut préférer les boucles for en général, qui sont plus lisibles et diminuent
les chances de faire des boucles infinies.

29/97
Opérations de base de python
Utilisation avancée des boucles

On peut générer des listes directement avec des boucles dans [].
Par exemple les 10 premiers nombres carrés.

squares = [i*i for i in range(10)]


print(squares)

Output :

[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

Il existe deux mots clés qu’on peut utiliser à l’intérieur d’une boucle pour
changer son déroulement :
break permet une sortie immédiate de la boucle
continue permet de passer à l’itération suivante
30/97
Opérations de base de python
If elif else

Une condition s’exprime avec if. Puis on peut la faire suivre avec des elif et
éventuellement finir par un else.

for i in range(3, 19, 4):


if i == 3:
print("i = 3")
elif i % 3 == 0:
print("i divisible par 3")
else:
print(i)

Output :

i = 3
7
11
i divisible par 3

31/97
Opérations de base de python
If elif else

Il existe aussi des mots clés pour faciliter la compréhension :


in pour vérifier qu’un élément est dans une liste
is peut remplacer ==
not pour la négation.

# "in" to check if an element is in a list


a = [1, 2, 3, 4]
if 2 in a:
print("2 in a")
# "is" for ==
if a[1] is 2:
print("a[1] is 2")
# "not" for the negation
if a[1] is not 3:
print("a[1] is not 3")

Output :

2 in a
a[1] is 2
a[1] is not 3 32/97
Opérations de base de python
Les fonctions

Le mot clé pour écrire une fonction est def, suivi du nom de la fonction et des
arguments entre parenthèse.
La fonction est ensuite définie dans le bloc commencé par def.

def write_hello():
print("Hello")

write_hello()

def write_hello_to(name):
print("Hello " + name)

write_hello_to("George")

Output :

Hello
Hello George

33/97
Opérations de base de python
Les fonctions

On peut écrire une documentation de la fonction au début du bloc, en écrivant un


commentaire multiligne. On peut accéder à la documentation avec help(function).
Ici, une fonction qui divise aa par bb et retourne le quotient avec le mot clé return.

def divide(a, b):


"""Divide a by b and return the quotient
a -- dividend
b -- divisor"""
return a // b

print(divide(10, 5))
print(divide(10.0, 9.0))
help(divide) # Or print(divide.__doc__)

Output :

2
1.0
Help on function divide in module __main__:

divide(a, b)
Divide a by b and return the quotient
a -- dividend
b -- divisor 34/97
Opérations de base de python
Fonction récusive

Voici l’exemple classique des fonctions récursives : la suite de Fibonacci.

F0 = 1, F1 = 1, ∀n ∈ N, n > 1, Fn = Fn−2 + Fn−1

def fibo(n):
"""Returns n-th term of the Fibonacci sequence"""
if n < 2:
return 1
else:
return fibo(n - 2) + fibo(n - 1)

for i in range(10):
print(f"Fibonacci number {i} is {fibo(i)}")

Fibonacci number 0 is 1
Fibonacci number 1 is 1
Fibonacci number 2 is 2
Fibonacci number 3 is 3
Fibonacci number 4 is 5
Fibonacci number 5 is 8
Fibonacci number 6 is 13
Fibonacci number 7 is 21
Fibonacci number 8 is 34
Fibonacci number 9 is 55
35/97
Opérations de base de python
Paramètres par défaut

On peut nommer les paramètres et leur donner une valeur par défaut. Cela
peut permettre plus de flexibilité et de lisibilité.
On va écrire une version différente de notre fonction de Fibonacci en
proposant de paramétrer les valeurs de F0 et F1 .

def fibo(n, f0=1, f1=1):


"""Returns n-th term of the Fibonacci sequence
f0 -- the value returned for 0 (1 by default)
f1 -- the value returned for 1 (1 by default)
"""
if n == 0:
return f0
if n == 1:
return f1

fnm2 = f0
fnm1 = f1
for i in range (1, n):
fn = fnm2 + fnm1
fnm2 = fnm1
fnm1 = fn

return fn

36/97
Opérations de base de python
Valeurs retournées multiples

On peut retourner plusieurs valeurs d’une fonction. return x, y va retourner


le couple (x,y).
On peut récupérer les valeurs retournées avec la syntaxe : x, y = fct().

import numpy as np

def cart_to_polar(x, y):


""" Returns (r, theta) polar coordinates of the point with cartesian coordinates
r = np.sqrt(x*x + y*y)
theta = np.arctan(y / x)
return r, theta

x, y = 1.33, 4.25
r, theta = cart_to_polar(x, y)

print("x, y", x, y)
print("r, theta", r, theta)

x, y 1.33 4.25
r, theta 4.45324600713 1.26750958302
37/97
Opérations de base de python
Utilisation avancée des fonctions

Définir une fonction locale dans une fonction (une lambda fonction).

def compute_fib_seq(n):
"""Compute the fibonacci sequence up to number n"""
f = [1, 1]

def next_fib(fib):
"""Add the two last values of the list fib and retuns it"""
f_m2 = fib[-2]
f_m1 = fib[-1]
return f_m2 + f_m1

for i in range(n-2):
f.append(next_fib(f))

return f

print(compute_fib_seq(7))
# next_fib cannot be called here

[1, 1, 2, 3, 5, 8, 13]

Cette fonction ne peut pas être appelée en dehors de la fonction mère. 38/97
Opérations de base de python
Modularité

Lorsque le code dépasse un certain nombre de lignes, on préfère le diviser


en plusieurs fichiers ou module.
Pour accéder au contenu d’un fichier dans un autre, ou pour charger une
bibliothèque installée dans l’environnement, on utiliser import

# mymodule.py
hello = "Hello wolrd"
constant = 23

def print_something():
print("something")

import mymodule

print(mymodule.hello)
print(mymodule.constant)
mymodule.print_something()

Output :

Hello wolrd
23
something 39/97
Opérations de base de python
Exercice

Write a program to display all prime numbers within a range

# range
start = 25
end = 50

Output :

Prime numbers between 25 and 50 are:


29
31
37
41
43
47

40/97
Opérations de base de python
Exercice

Write a program to display all prime numbers within a range

start = 25
end = 50
print("Prime numbers between", start, "and", end, "are:")

for num in range(start, end + 1):


# all prime numbers are greater than 1
# if number is less than or equal to 1, it is not prime
if num > 1:
for i in range(2, num):
# check for factors
if (num % i) == 0:
# not a prime number so break inner loop and
# look for next number
break
else:
print(num)

41/97
Lecture et écriture de fichier

L’ouverture d’un fichier se fait avec open, qui prend en paramètre le nom du
fichier à ouvrir et le mode d’ouverture :

”r” pour lecture seule (option par défaut)


”w” pour l’écriture en écrasant le fichier s’il existe
”w” comme ”w”, mais renvoie une erreur si le fichier existe déjà
”a” pour l’écriture en ajoutant à la fin du fichier déjà existant
”+” pour lecture et écriture du fichier

La fonction renvoie l’objet python associé au fichier. Il faut ensuite utiliser


close() pour le fermer.

42/97
Lecture et écriture de fichier
Pour écrire une chaı̂ne de caractères dans le fichier, on peut utiliser write.
Pour lire une ligne, on peut utiliser readline.

f = open("file.txt", "w")
f.write("One\n") # utiliser \n pour sauter une ligne
f.write("Two")
line = f.readline()
print(line)
f.close()

Output :

One
Two

43/97
Algèbre
Nombres complexes

On peut créer un nombre complexe avec la fonction complex() ou


directement en utilisant j pour la partie imaginaire.

#Create a complex number


z = complex(2, 1)
x = 2.0 + 1.0j
print("z", z)
print(x == z)
print("x + z", x + z)
print("x - z", x - z)
print("xz", x * z)

Output :

z (2+1j)
True
x + z (4+2j)
x - z 0j
xz (3+4j)

44/97
Algèbre
Nombres complexes

On peut ensuite accéder séparement à la partie réelle avec .real et la partie


imaginaire avec .imag

z = complex(2, 1)
print("Real part is :", z.real)
print("Imaginary part is :", z.imag)

Output :

Real part is : 2.0


Imaginary part is : 1.0

45/97
Algèbre
Numpy

La bibliothèque numpy étend largement les possibilités de base de python


pour le calcul numérique. Elle est bien documentée et optimisée.
En général, on importe numpy de la façon suivante :

import numpy as np

Pour plus de lisibilité, cette ligne ne sera plus écrite au début de chaque
exemple, mais bien présente néanmoins.

46/97
Algèbre
Array numpy

Les tableaux numpy sont des ”vrais” tableaux : tous les éléments ont le même
type, on peut accéder à un élement avec [] comme pour la liste.
L’avantage majeur de ces tableaux est qu’ils permettent de faire des
opérations vectorisées et optimisées qui s’approchent des performances qu’on
pourrait attendre d’un code compilé.

import numpy as np
t = np.array([1, 2, 3]) # Create numpy array from python list
print(t)
print(type(t))

Output :

[1 2 3]
<class 'numpy.ndarray' >

47/97
Algèbre
Array numpy : tableaux

Il existe plusieurs manières de créer un tableau numpy :

# From a list: as we saw before


# Uninitialized values (faster)
t2 = np.empty(3)
print(t2)
# Initiliazed to a value (safer)
t_0 = np.zeros(3)
print(t_0)
t_1 = np.ones(3)
print(t_1)
t_22 = np.full(3, 22)
print(t_22)

Output :

[ 6.91901375e-310 6.91901375e-310 6.91900916e-310]


[ 0. 0. 0.]
[ 1. 1. 1.]
[22 22 22]
48/97
Algèbre
Array numpy : tableaux

Il existe une multitude d’autres fonctions pour générer des tableaux. On peut
noter arange, l’équivalent de range, mais qui fonctionne aussi avec des
nombres réels

print(np.arange(4)) # Last element (first = 0, step = 1)


print(np.arange(1.5, 6.3)) # First and last (step = 1)
print(np.arange(1.5, 5, 0.5)) # First, last, step

Output :

[0 1 2 3]
[ 1.5 2.5 3.5 4.5 5.5]
[ 1.5 2. 2.5 3. 3.5 4. 4.5]

49/97
Algèbre
Array numpy : tableaux

Tous les éléments d’un tableau ont le même type. On peut le retrouver avec la
syntaxe .dtype

a = np.arange(4)
print(a.dtype)

b = np.arange(4.0)
print(b.dtype)

Output :

int64
float64

50/97
Algèbre
Array numpy : tableaux

Il est parfois nécessaire de préciser le type que l’on veut utiliser. Sans rien
préciser, on peut avoir des surprises :

a = np.arange(4)
print(a)

# Let's divide all elements by 2


for i in range(len(a)):
a[i] = a[i] / 2.0 # Integer division because a[i] has to be integer

print(a)

Output :

[0 1 2 3]
[0 0 1 1]

51/97
Algèbre
Array numpy : tableaux

Pour préciser le type à l’initialisation on utiliser l’argument dtype=

a = np.arange(4, dtype='f') # 'f' for float


print(a)

# Let's divide all elements by 2


for i in range(len(a)):
a[i] = a[i] / 2.0 # Real division because a[i] is float

print(a)
print(a.dtype)

Output :

[ 0. 1. 2. 3.]
[ 0. 0.5 1. 1.5]
float32

52/97
Algèbre
Array numpy : tableaux

Les principaux types sont :


’f’ ou ’f4’ : réels sur 4 octets (float)
’d’ ou ’f8’ : réels sur 8 octets (double)
’i’ : entier (’i4’ ou ’i8’ si on veut préciser le nombre d’octets)
’c’ : complex (’c8’ ou ’c16’)
’ ?’ : boolean
Ils marchent en général pour toutes les initialisations de tableaux

53/97
Algèbre
Array numpy : tableaux

On ne peut pas changer le type d’un tableau, mais on peut facilement le copier
dans le bon type

ti = np.arange(3)
print(ti.dtype, ti)

tc = np.array(ti, dtype='c8')
print(tc.dtype, tc)

tb = np.array(ti, dtype='?')
print(tb.dtype, tb)

Output :

int64 [0 1 2]
complex64 [ 0.+0.j 1.+0.j 2.+0.j]
bool [False True True]

54/97
Algèbre
Opérations sur tout le tableau

On peut appliquer une opération arithmétique sur tous les éléments du


tableau directement.

a = np.arange(5, dtype='d')
print(a)

a = a / 2 # Divide all elements by 2


print(a)

a /= 2 # Same thing
print(a)

Output :

[ 0. 1. 2. 3. 4.]
[ 0. 0.5 1. 1.5 2. ]
[ 0. 0.25 0.5 0.75 1. ]

55/97
Algèbre
Opérations sur tout le tableau

On peut faire des opérations terme à terme sur 2 tableaux de même taille

a = np.arange(5)
b = np.arange(0, 50, 10)
print(a)
print(b)
print(a + b)

Output :

[0 1 2 3 4]
[ 0 10 20 30 40]
[ 0 11 22 33 44]

On a une erreur si taille n’est pas la même.

56/97
Algèbre
Opérations sur tout le tableau

Enfin, on peut utiliser les tableaux comme des vecteurs. On peut par exemple
faire un produit scalaire avec .dot

a = np.arange(3.0)
b = np.arange(3.0, 6.0)
print(a)
print(b)
print(a.dot(b))

Output :

[ 0. 1. 2.]
[ 3. 4. 5.]
14.0

57/97
Algèbre
Nd-arrays

Les tableaux vu précédemment peuvent aussi se décliner en tableaux à n


dimension : les ndarray. Les dimensions du tableau sont appelées shape. On
peut y accéder avec .shape. Les tableaux précédents sont bien des ndarray
de dimension 1.

a = np.array([1, 2, 3])
print(a.shape)
print(type(a))

Output :

(3,)
<class 'numpy.ndarray' >

Remarque : pour une seule dimension, la shape d’un tableau de taille n est
noté (n,).

58/97
Algèbre
Nd-arrays

En plusieurs dimensions

a = np.array([[1, 2, 3], [-1, 3, 3]])


print(a)
print(a.shape)

b = np.array([[[0,0],[0,0]], [[0,0],[0,0]], [[0,0],[0,0]]], dtype='d')


print("\n", b)
print(b.shape)

Output :

[[ 1 2 3]
[-1 3 3]]
(2, 3)

[[[ 0. 0.]
[ 0. 0.]]

[[ 0. 0.]
[ 0. 0.]]

[[ 0. 0.]
[ 0. 0.]]]
(3, 2, 2) 59/97
Algèbre
Nd-arrays

Ou encore...

print(np.zeros((3,)), "\n") # 1D
print(np.ones((2, 2)), "\n") # 2D
print(np.full((3, 2, 2), 10), "\n") # 3D
#On peut toujours accéder à un élément avec [], mais il faut préciser chaque dimension.
a = np.ones((3, 2, 2))
print(a[2,0,1])

[ 0. 0. 0.]

[[ 1. 1.]
[ 1. 1.]]

[[[10 10]
[10 10]]

[[10 10]
[10 10]]

[[10 10]
[10 10]]]

1.0

60/97
Algèbre
Nd-arrays

Il existe une multitude de fonctions pour changer la shape de tels tableaux. A


noter qu’on ne peut pas changer la taille totale de données. La fonction
canonique pour cette opération est reshape().

a = np.arange(12.0)

a = a.reshape(3, 4)
print(a, '\n---\n')

a = a.reshape(3, 2, 2)
print(a)

[[ 0. 1. 2. 3.]
[ 4. 5. 6. 7.]
[ 8. 9. 10. 11.]]
---

[[[ 0. 1.]
[ 2. 3.]]

[[ 4. 5.]
[ 6. 7.]]

[[ 8. 9.]
[ 10. 11.]]]

61/97
Algèbre
Slicing

On peut faire des opérations sur des sous-parties d’un ndarray en utilisant le
slicing. Il s’agit de préciser un ensemble d’indices avec la syntaxe first :last
où first est le premier indice et last est l’indice du dernier élement +1.

a = np.arange(5.0)
print(a)

# Add ten for values 1 and 2


a[1:3] += 10
print(a)

# Set values 3 and 4 to 40


a[3:5] = 40
print(a)

Output :

[ 0. 1. 2. 3. 4.]
[ 0. 11. 12. 3. 4.]
[ 0. 11. 12. 40. 40.]
62/97
Algèbre
Slicing

Si on ne présise pas first ou last, python prend par défaut le début et la fin
du tableau dans cette dimension. On peut même utiliser la syntaxe
first :last :step pour accéder aux éléments d’indices séparés de step.

a = np.arange(5.0)
print(a)
# Set array to 10 up to the 3rd value
a[:3] = 10.0
print(a)

numbers = np.arange(30)
print(numbers)

mult_of_4 = numbers[0 : len(numbers) : 4]


print(mult_of_4)

[ 0. 1. 2. 3. 4.]
[ 10. 10. 10. 3. 4.]
[ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
25 26 27 28 29]
[ 0 4 8 12 16 20 24 28]
63/97
Algèbre
Slicing

Et en plusieurs dimensions, on peut utiliser cette syntaxe pour extraire une


sous-partie du tableau. Pour un tableau en 2D, on peut par exemple extraire
une ligne, une colonne ou un bloc facilement

a = np.arange(12.0).reshape(3, 4)
print(a, "\n")
# Extract 2nd line
print(a[1, :], "\n")
# Extract 3rd column
print(a[:, 2], "\n")

Output :

[[ 0. 1. 2. 3.]
[ 4. 5. 6. 7.]
[ 8. 9. 10. 11.]]

[ 4. 5. 6. 7.]

[ 2. 6. 10.]
64/97
Algèbre
Matrices

En python 2 et 3, le produit matrice-vecteur ou matrice-matrice utilise la


syntaxe .dot comme pour le produit scalaire.

A = np.arange(4.0).reshape(2, 2)
print("A\n", A, "\n")
x = np.array([1.0, -2.0])
print("x\n", x, "\n")
print("Ax\n", A.dot(x), "\n")
B = np.array([[1.0, 1.0], [0.0, 1.0]])
print("B\n", B, "\n")
print("AB\n", A.dot(B))

A
[[ 0. 1.]
[ 2. 3.]]
x
[ 1. -2.]
Ax
[-2. -4.]
B
[[ 1. 1.]
[ 0. 1.]]
AB
[[ 0. 1.]
[ 2. 5.]]
65/97
Algèbre
Matrices

En python 3 (à partir de la version 3.5 seulement) a été ajouté l’opérateur @.


Celui-ci permet d’écrire A @ B au lieu de A.dot(B), ce qui est plus lisible si
on fait plusieurs multiplications à la suite.

A = np.arange(4.0).reshape(2, 2)
B = np.arange(-2.0, 2).reshape(2, 2)
x = np.array([1, 2])

# Python 3.5
# A B x
print A.dot(B.dot(x))
print(A @ B @ x)

Output :

[ 2. -2.]
[ 2. -2.]

66/97
Algèbre
Matrices

Lorsqu’on mélange les vecteurs et les matrices, il faut parfois faire attention
aux dimensions des objets manipulés. Si on extrait une ligne et une colonne
d’une matrice, on obtient dans les 2 cas un tableau 1D.

A = np.arange(4.0).reshape(2, 2)
print(A, '\n')

A_r1 = A[0,:]
print("row 1", A_r1, '\n')

A_c1 = A[:,0]
print("col 1", A_c1, '\n')

Output :

[[ 0. 1.]
[ 2. 3.]]

row 1 [ 0. 1.]

col 1 [ 0. 2.]
67/97
Algèbre
Matrices

Il semble donc qu’on ait pas l’information exacte de ce qui est extrait. Pour
garder l’information ligne ou colonne, on peut être tenté de tout passer en 2D.

A = np.arange(4.0).reshape(2, 2)
print(A, '\n')

A_r1 = A[0,:].reshape((1, -1))


print("row 1\n", A_r1, '\n')

A_c1 = A[:,0].reshape((-1, 1))


print("col 1\n", A_c1, '\n')

[[ 0. 1.]
[ 2. 3.]]

row 1
[[ 0. 1.]]

col 1
[[ 0.]
[ 2.]]
68/97
Algèbre
Matrices

Mais il faut alors faire attention quand on fait des produits scalaires ! !

UT = np.arange(3.).reshape(1, 3)
V = np.full((3,1), -1)
print("U^T\n", UT, '\n')
print("V\n", V, '\n')

result = UT.dot(V) # Or UT @ V

print("U^T V\n", result, '\n') # On obtient alors une matrice (1,1)


print(result.shape)
print(result.item()) # Pour revenir à un scalaire

U^T
[[ 0. 1. 2.]]

V
[[-1]
[-1]
[-1]]

U^T V
[[-3.]]

(1, 1)
3.0 69/97
Algèbre
Matrices

Il existe des fonctions spécialisées pour créer des matrices. Par exemple pour
la matrice identité, on peut utiliser identity (matrice carrée) ou eye (génère
une matrice avec des 1 sur la diagonale).

print(np.eye(3, 4), "\n")


print(np.identity(3))

Output :

[[ 1. 0. 0. 0.]
[ 0. 1. 0. 0.]
[ 0. 0. 1. 0.]]

[[ 1. 0. 0.]
[ 0. 1. 0.]
[ 0. 0. 1.]]

70/97
Algèbre
Matrices

On peut utiliser diag() pour extraire la diagonale dans un tableau 1D.


Pour transposer une matrice, on peut utiliser transpose() ou .T.
On peut utiliser linalg.inv() pour calculer l’inverse d’une matrice.

A = np.arange(9.).reshape(3,3)
print(A, "\n")
print(np.diag(A), "\n")
print(A.T) # Ou np.transpose(A)

Output :

[[ 0. 1. 2.]
[ 3. 4. 5.]
[ 6. 7. 8.]]

[ 0. 4. 8.]

[[ 0. 3. 6.]
[ 1. 4. 7.]
[ 2. 5. 8.]]
71/97
Algèbre
Copies VS références

En python, il n’est pas toujours évident de savoir ce qu’il se passe quand on


écrit pour deux objets A et B l’affectation B = A :
A et B sont deux copies indépendentes
A et B sont deux références vers le même objet
Exemple avec deux entiers :

A = 18
B = A
B = 22
print(A)
print(B)

18
22

Comme on s’y attend, on a en mémoire un nombre A et un nombre B, et


B=A a bien copié la valeur de A dans B.
72/97
Algèbre
Copies VS références

Essayons maintenant avec des tableaux :

A = np.arange(3)
B = A
B[2] = 18
print(A)
print(B)

Output :

[ 0 1 18]
[ 0 1 18]

Visiblement, A et B sont deux références vers le même tableau en mémoire :


écrire A[2] = 18 ou B[2] = 18 est donc équivalent après avoir fait B = A.

Cela peut être source d’erreur !


Parfois on veut vraiment une copie distincte de l’originale.
73/97
Algèbre
Copies VS références

Ce comportement peut être expliqué par le fait qu’il est en coûteux de copier
des tableaux en mémoire, et on préfère manipuler des références vers ceux-ci.

On a le même comportement quand on utilise le slicing :

A = np.arange(5)
print(A)

even = A[0:len(A):2]
print(even)

even[1] = 33
print(even)

print(A)

[0 1 2 3 4]
[0 2 4]
[ 0 33 4]
[ 0 1 33 3 4]
74/97
Algèbre
Copies VS références

Ou même la transposition d’une matrice. . .

A = np.arange(9).reshape(3,3)
print(A, '\n')

At = A.T

At[1,2] = 18
print(At, '\n')
print(A)

[[0 1 2]
[3 4 5]
[6 7 8]]

[[ 0 3 6]
[ 1 4 18]
[ 2 5 8]]

[[ 0 1 2]
[ 3 4 5]
[ 6 18 8]]
75/97
Algèbre
Copies VS références

On peut expliciement demander une copie, soit en appelant une fonction de


construction de l’objet, soit en utilisant copy() de numpy.

A = np.arange(3)

B = np.array(A)
B[2] = 18

C = np.copy(B)
C[1] = -9

print(A)
print(B)
print(C)

[0 1 2]
[ 0 1 18]
[ 0 -9 18]

76/97
Algèbre
Scipy

La plupart des fonctions plus poussées d’algèbre linéaire vont fonctionner


sur ces objets numpy.
Elles sont définies dans la bibliothèque dédiée au calcul scientifique de
python : scipy.
scipy.linalg contains all the functions in numpy.linalg. plus some other
more advanced ones not contained in numpy.linalg.
En particulier, le module scipy.linalg est très intéressant.
Toutes les opérations d’algèbre linéaire avancées sont décrites dans la
documentation de scipy.linalg (calcul de déterminant, de norme, de
pseudo-inverse, décomposition en valeurs propres ou en valeurs
singulières...)

import numpy as np
import scipy as sp
import scipy.linalg as spl

77/97
Algèbre
Scipy

Basics :
inv(A) : Compute the inverse of a matrix.
solve(A,b) : Solves the linear equation set Ax = b for the unknown x for
square A matrix.
solve triangular(A,b) : Solve the equation Ax = b for x, assuming A is
a triangular matrix.
det(A) : Compute the determinant of a matrix.
norm(A) : Matrix or vector norm.
lstsq(A,b) : Compute least-squares solution to equation Ax = b.
kron(a,b) : Kronecker (tensor) product between a and b.

78/97
Algèbre
Scipy

Eigenvalue Problems :
eig(A) : Solve an eigenvalue problem (find eigenvalues, and right or left
eigenvectors) of a square matrix.
eigvals(A) : Compute eigenvalues from an eigenvalue problem.
Decompositions :
lu(A) : Compute pivoted LU decomposition of a matrix.
lu solve(LU A,b) : Solve an equation system, Ax = b, given the LU
factorization of A
qr(A) : Compute QR decomposition of a matrix.
rq(A) : Compute RQ decomposition of a matrix.
Matrix Equation Solvers :
solve sylvester(A,B,Q) : Computes a solution X to the Sylvester
equation AX + XB = Q

79/97
Algèbre
Scipy

Soit A une matrice carrée n × n, b un vecteur de taille n. On veut trouver le


vecteur x tel que Ax = b.

A = np.array([[2, -1, 0],[-1, 2,-1],[0, -1, 2]], dtype='d')


print("A\n", A, "\n")
b = np.array([3.0, 0., 1.])
print("b", b, "\n")
print("x such that Ax = b")
x = spl.solve(A, b)
print(x)
print("\nAx =")
print(A @ x)

A
[[ 2. -1. 0.]
[-1. 2. -1.]
[ 0. -1. 2.]]

b [ 3. 0. 1.]

X such that Ax = b
[ 2.5 2. 1.5]

Ax =
[ 3.00000000e+00 2.22044605e-16 1.00000000e+00]
80/97
Plotting (matplotlib)
Utilisation basique

Pour faire des graphiques en python, on peut utiliser la bibliothèque


matplotlib., en particulier le module pyplot.
L’utilisation est la suivante :
importer matplotlib
définir un plot
afficher le plot avec plt.show() ou le sauvegarder dans un fichier avec
plt.savefig(”file.png”)

import numpy as np
import matplotlib.pyplot as plt

x = np.arange(-np.pi, np.pi, 0.01)


plt.plot(x, np.sin(x))

plt.savefig("file1.png")
plt.show()

81/97
Plotting (matplotlib)
Utilisation basique

On a ici fait l’utilisation la plus basique avec deux tableaux (ou listes) de
même taille X et Y , on a fait plot(X,Y).

82/97
Plotting (matplotlib)
Utilisation basique

Pour mettre plusieurs courbes, on fait plusieurs plot.

x = np.arange(-np.pi, np.pi, 0.01)


plt.plot(x, np.sin(x))
plt.plot(x, np.cos(x))
plt.plot(x, -1*np.cos(x))

plt.savefig("file2.png")
plt.show()

83/97
Plotting (matplotlib)
Utilisation basique

84/97
Plotting (matplotlib)
Personnalisation des courbes

La fonction plot peut prendre un grand nombre de paramètres pour


personnaliser les courbes.

On peut notamment noter :


color la couleur de la courbe
linestyle (’-’, ’–’, ’-.’, ’ :’, ”,). Avec ” (ou None), on ne trace
linewidth la taille de la ligne (ou des symboles)
marker pour définir le type de point (markersize pour la taille)
label pour la légende de la courbe

85/97
Plotting (matplotlib)
Personnalisation des courbes

x = np.arange(0, 1, 0.1) # 10 points


plt.plot(x, np.sin(x), color="black", linestyle="--")
plt.plot(x, np.cos(x), color="purple", linestyle=":")
plt.plot(x, -1*np.cos(x), marker="o", color="green", markersize=3)
plt.plot(x, (x-1)/2, linestyle="", marker="o", color="blue", markersize=7)

plt.savefig("file3.png")
plt.show()

86/97
Plotting (matplotlib)
Personnalisation des courbes

87/97
Plotting (matplotlib)
Personnalisation des axes

On peut utiliser xlabel et ylabel pour rajouter des informations sur les axes.
Pour afficher la légende, on utilise legend.

x = np.arange(0, 1, 0.1) # 10 points


plt.plot(x, np.sin(x), color="black", linestyle="--", label="Sinus")
plt.plot(x, np.cos(x), color="purple", linestyle=":", label="Cosinus")

plt.xlabel("x axis")
plt.ylabel("y axis")
plt.legend()

plt.savefig("file4.png")
plt.show()

88/97
Plotting (matplotlib)
Personnalisation des axes

Pour choisir les valeurs minimales et maximales pour les axes, on utilise
axis([xmin, xmax, ymin, ymax]). 89/97
Plotting (matplotlib)
Personnalisation des axes

En ajoutant cette ligne de code


plt.axis([0.7, 0.9, 0.6, 0.8])

90/97
Plotting (matplotlib)
Subplots

plt.subplot permet de définir des graphes les uns à côté des autres.
Les arguments sont nrows, ncols, index.
Les sous-graphes seront placés selon leur index de gauche à droite et de
haut en bas, sur une grille nrows×ncols.
plt.figure(figsize=(1, 1)) crée une image “inch-by-inch”.
plt.suptitle(”title”) crée une titre global

91/97
Plotting (matplotlib)
Subplots

plt.figure(figsize=(9, 3))

lims = [-np.pi/3, np.pi/3, -1.1, 1.1]

x = np.arange(-np.pi/3, np.pi/3, 0.01)

plt.subplot(131)
plt.plot(x, np.sin(x), label="Sinus")
plt.axis(lims)
plt.legend()

plt.subplot(132)
plt.plot(x, np.cos(x), label="Cosinus")
plt.axis(lims)
plt.legend()

plt.subplot(133)
plt.plot(x, np.tan(x), label="Tangent")
plt.axis(lims)
plt.legend()

plt.suptitle("trigonometric functions")

plt.savefig("file6.png")
plt.show()
92/97
Plotting (matplotlib)
Subplots

93/97
Plotting (matplotlib)
Barplots

On utilise bar pour faire un graphe en barres, avec les clés en abscisses et les
valeurs en ordonnées.

computers = ["Supercomputer Fugaku", "Summit", "Sierra ", "Sunway TaihuLight", "Selene"]


rpeak = [537212.0, 200794.9, 125712.0, 125435.9, 79215.0]

plt.figure(figsize=(9, 4))
plt.bar(computers, rpeak)

plt.xlabel("Supercomputer (source: top500, June 2019)", fontsize=13)


plt.ylabel("Rpeak (TFlop/s)", fontsize=13)

plt.savefig("file7.png")
plt.show()

94/97
Plotting (matplotlib)
Barplots

95/97
Plotting (matplotlib)
Exercice

Obtenir ce graphe

à partir de :
boxoffice = {
"I": 1027,
"II": 649.4,
"III": 848.7,
"IV": 775.4,
"V": 538.3,
"VI": 475.1,
"VII": 2068,
"VIII": 1332,
"XI": 1074
} 96/97
Dernier exercice
Résoudre une équation d’advection linéaire

Soit u(x, t) : R × R+ → R, x ∈ R, t ∈ R+ , a ∈ R+
∂u ∂u
+a =0
∂t ∂x
Considérez le domaine x ∈ [−1, 1], une vitesse d’advection a = 0.3, jusqu’au
temps tf in = 2.5. Partir d’une condition initiale
2
u(x, 0) = u0 (x) = e−1/(1−(x/0.1) )

Résoudre l’équation avec une méthode de différence finie avec ∆x = 0.001

un+1 − uni un − uni−1 a∆t n


i
+a i = 0 =⇒ un+1 = uni − (u − uni−1 )
∆t ∆x i
∆x i
Le pas de temps est dicté par la condition de Courant-Friedrichs-Lewy
a∆t ∆x
CF L = = 0.8 < 1 =⇒ ∆t = CF L
∆x a
condition aux limites périodique pour le nœud 1 : un+1
1 = un1 − a∆t n
∆x (u1 − unN97/97
)

Vous aimerez peut-être aussi