Please wait, while our marmots are preparing the hot chocolate…
# @chunk: chunks/title.md
# @chunk: chunks/objectives.md
## Informatique {var-cours-n} : Plan {#plan overview}
- Logistique : rappels {tp}
- Bibliothèque Numpy : premier contact {numpyintro}
- Numpy : type, *shape*, agrégations {nptypeshapeagg}
- Numpy : opérations élément par élément {npsimpleop}
- Listes Python : tranches {listslicing}
- Numpy : indices et tranches {npslicing}
- Bibliothèque Matplotlib : premier contact {matplotlibintro}
# @copy:#plan: %+class:inred: .tp
## Rendus de TP {libyli}
- Typiquement 2 rendus
- premier rendu en fin de séance
- second rendu libre, avant le lundi mardi suivant 5h00 (matin)
- Comment rendre
- créez un fichier .zip
- aller sur claroline connect
- aller dans ressource « Rendu TP... »
- envoyez votre fichier zip
- (ne pas supprimer l'ancien s'il y en a déjà un)
- Que rendre ?
- fichier zip avec le code python, le compte rendu, etc (voir énoncé de TP)
- bien penser à vos noms (les 2 pour un binôme) dans le compte rendu
- ⚠ fichiers absents, nom manquant, ... ⇒ comme si pas rendu
- NB: si le « rendu TP... » n'existe pas encore, me le dire
- RAPPEL: examen de TP personnel (pas de binôme)
## Points importants sur le TP3 {libyli}
- Avoir compris le calcul flottant
- python ne peux pas représenter tous les nombres réels
- certains nombres sont donc arrondis (type float)
- il est donc inadapté de comparer des nombres avec `==`
- Avoir bien compris `assert`, par exemple `assert «expr»`
- instruction python qui vérifie que `«expr»` est vraie
- génère une erreur si `«expr»` est fausse
- (NB: toute erreur interrompt le programme)
- Avoir pris connaissance de `numpy.testing.assert_allclose`
- (renommé `assert_egal` dans le TP3)
- fonction qui reçoit 2 paramètres
- vérifie que ces deux paramètres sont (à peu près) égaux
- gère les nombres flottant presque égaux
- gère les listes et tableau numpy
- ⚠ L'examen pratique utilisera `assert` etc.
# @copy:#plan: %+class:inred: .numpyintro
## Numpy {libyli}
- Motivation
- `les_carrés`, `les_logs`, ...
- `liste_zeros2d`, `grille`, ...
- simplifié grâce aux « listes en compréhension » ⇒ peut mieux faire
- \+ performances (vitesse de calcul)
- Bibliothèque Numpy (module `numpy`)
- structure de données pour des tableaux à 1, 2, n dimensions
- simplification des calculs
- fonctions utilitaire pour les opérations classiques
- bases de nombreuses autres bibliothèques
## Numpy, ex. : création de tableaux de 0 {libyli}
- Exemple (atypique, préférer la version d'en bas)
```python
import numpy
a = numpy.zeros(6) # "vecteur" avec 6 zéros
print(a)
b = numpy.zeros([5, 10]) # tableau de 5 lignes et 10 colonnes
print(b)
{slide}
```
- Version typique (`np` et utilisation de « tuple » (n-uplet))
```python
import numpy as np
a = np.zeros(6)
print(a)
b = np.zeros((5, 10))
print(b)
{slide}
```
- NB: `(5, 10)` est un **n-uplet (ou *tuple*)** qui se comporte comme la liste `[5, 10]` mais n'est pas modifiable (erreur si on essaie de changer une valeur)
## Numpy : quelques fonctions de création
- `np.zeros(n)`
- `np.zeros(shape)` (*shape* ⇔ forme ⇔ dimensions du tableau)
- et `np.one(...)`
- `np.arange(n)`
- `np.arange(a, b)`
- `np.arange(a, b, s)`
- `np.eye(n)`
- `np.eye(n1, n2)`
- `np.random.random(n)`
- `np.random.random(shape)`
- `np.random.uniform(a, b, shape)`
- `np.random.normal(moyenne, ecart_type, shape)`
- ...
## Numpy : opérations {libyli}
- La plupart des opération (`+`, `-`, `*`, ...) sont effectuée élément par élément
- entre deux tableaux numpy `a + b`
- entre un tableaux et un nombre `a + 10` (ajoute 10 à chaque élément de `a`)
- La plupart des fonctions de `math` ont un équivalent dans numpy
- ex : `np.log(a)`
- Numpy propose des fonction d'agrégation
- ex : `np.sum(a)`, `np.mean(a)`, `np.median(a)`, etc.
```python
import numpy as np
a = np.random.uniform(0.5, 1, (7, 4))
b = np.random.uniform(10, 20, (7, 4))
print(a + b)
print(a + 10)
print(a**b)
print(np.sum(a))
print(np.sum(a, axis=0)) # plus tard...
{slide}
```
# @copy:#plan: %+class:inred: .nptypeshapeagg
# @chunk: chunks/q/np-access-1.md
# @chunk: chunks/q/np-access-2.md
## Numpy : création et *shape* (forme, dimensions) {libyli}
```python
import numpy as np
a = np.ones((3, 8))
b = np.arange(0, 100, 5)
c = np.arange(0.5, 100, 5)
d = np.array([10, 15, 3.14, 2.7, 9.81])
{slide}
```
- Tableau numpy : type `ndarray` et type des éléments
- `ndarray` tableau à n dimensions
- types numériques python : int64, float64, bool, ...
```python
print( type(a), type(b), type(c) ) # numpy.ndarray (les trois)
print( a.dtype, b.dtype, c.dtype ) # float64 int64 float64
{slide}
```
- *shape* ⇔ forme ⇔ dimensions de tableau numpy
```python
print(a.shape) # (3,8) 2-uplet (paire) avec 3 et 8
print(b.shape) # (20,) 1-uplet contenant la valeur 20
print(c.shape) # (20,)
{slide}
```
- Indice multiples (autant que de dimensions)
```python
print(a[0, 0])
print(b[0])
a[1, 1] = a[2, 2] + 999
{slide}
```
# @chunk: chunks/q/np-shape-1.md
# @chunk: chunks/q/np-shape-2.md
## Numpy : *reshape* et données partagées et *copy* {libyli}
- Changement de forme avec `.reshape(shape)`
```python
a = np.array([1, 2, 3, 10, 20, 30])
b = a.reshape((2, 3)) # réorganiser en 2 lignes de 3 el.
# équivalent, calcul auto. de la dimension manquante
b = a.reshape((2, -1))
b = a.reshape((-1, 3))
{dense slide}
```
- ⚠️ Les tableaux partagent leurs données (idem pour les listes)
```python
print(a[0]) # 1
b[0,0] = 3.14
print(a[0]) # 3.14
l = [1, 2 ,3] # idem en numpy sans reshape ou avec listes
# idem si : l = np.array([1, 2, 3])
v = l
v[0] = 3.14
print(l[0]) # 3.14
{dense slide}
```
- Copier un tableau avec `.copy()`
```python
a[0] = 1
c = a.copy()
c[0] = 3.14
print(a[0]) # 1
{dense slide}
```
## Numpy : fonctions d'agrégations {libyli}
```python
a = np.random.uniform(0.95, 1.05, (20, 50))
print(a.shape) # (20, 50)
print(a.size) # 1000
{slide}
```
```python
print(np.sum(a)) # ≈ 1000
{slide}
```
```python
print(np.mean(a)) # ≈ 1
print(np.var(a)) # ≈ 0.0008333 (0.1² / 12)
print(np.std(a)) # = np.var(a) ** 0.5
{slide}
```
```python
print(np.min(a)) # ≳ 0.95
print(np.max(a)) # ≲ 1.05
{slide}
```
- Indice du min/max
```python
b = np.array([[10, 20, 30],
[60, 50, 40]])
print(np.argmin(b)) # 0
bligne = b.reshape((-1,))
print(np.argmax(bligne)) # 3
print(np.argmax(b)) # 3 (comme si en ligne)
print(np.unravel_index(np.argmax(b), b.shape)) # (1, 0)
{slide}
```
# @copy:#plan: %+class:inred: .npsimpleop
## Opérations élément par élément {libyli}
- Créons deux tableaux de même dimensions
```python
a = np.arange(0, 1000, 100).reshape((2, 5))
b = np.arange(0, 10).reshape((2, 5))
assert_allclose(a, np.array([[ 0, 100, 200, 300, 400],
[500, 600, 700, 800, 900]]))
assert_allclose(b, np.array([[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9]]))
{slide}
```
- Opérations éléments par élément
```python
c = a + b
assert_allclose(c, np.array([[ 0, 101, 202, 303, 404],
[505, 606, 707, 808, 909]]))
d = a * b
assert_allclose(d, np.array([[ 0, 100, 400, 900,1600],
[2500,3600,4900,6400,8100]]))
{slide}
```
```python
print(a / b)
# [[ nan 100. 100. 100. 100.]
# [ 100. 100. 100. 100. 100.]]
# nan : « not a number » (valeur spéciale, « pas un nombre »)
{slide}
```
## Opérations entre un tableau et un nombre {libyli}
- Créons un tableaux
```python
a = np.arange(0, 1000, 100).reshape((2, 5))
assert_allclose(a, np.array([[ 0, 100, 200, 300, 400],
[500, 600, 700, 800, 900]]))
{slide dense}
```
- Opérations avec un nombre
```python
print(a + 1) # ou 1 + a
# [[ 1 101 201 301 401]
# [501 601 701 801 901]]
print(a / 100) # ou a*0.01 ou 0.01*a
# [[ 0. 1. 2. 3. 4.]
# [ 5. 6. 7. 8. 9.]]
print(a**2)
# [[ 0 10000 40000 90000 160000]
# [250000 360000 490000 640000 810000]]
print(100 / a)
# [[ inf 1. 0.5 0.3333 0.25 ]
# [ 0.2 0.1667 0.14285714 0.125 0.1111]]
#
# inf : « infinity » (infini)
{slide}
```
## Fonctions mathématiques sur chaque élément {libyli}
- Créons un tableaux
```python
a = np.arange(0, 600, 100).reshape((2, 3))
assert_allclose(a, np.array([[ 0, 100, 200],
[300, 400, 500]]))
{dense slide}
```
- Fonctions mathématiques du module `numpy` …
```python
print(np.sin(a))
# [[ 0. -0.50636564 -0.8732973 ]
# [-0.99975584 -0.85091936 -0.46777181]]
print(np.cos(np.radians(a)))
# [[ 1. -0.17364818 -0.93969262]
# [ 0.5 0.76604444 -0.76604444]]
print(np.log(a))
# [[ -inf 4.60517019 5.29831737]
# [ 5.70378247 5.99146455 6.2146081 ]]
print(np.exp(a))
# [[ 1.00000000e+000 2.68811714e+043 7.22597377e+086]
# [ 1.94242640e+130 5.22146969e+173 1.40359222e+217]]
print(np.clip(a, 150, 350))
# [[150 150 200]
# [300 350 350]]
...
# https://docs.scipy.org/doc/numpy/reference/routines.math.html
# (^ pas que des opération élément par élément)
{dense slide}
```
# @copy:#plan: %+class:inred: .listslicing
## Tranches de listes Python {libyli}
- Rappel : accès à un élément d'une liste `la_liste[l_indice]`
```python
a = [0, 10, 20, 30, 40, 50, 60, 70, 80, 90]
print(a[3]) # 30
{slide}
```
- Extraction d'une sous partie de liste
```python
b = a[3:6]
print(b) # [30, 40, 50]
# avec un pas de 2
c = a[3:6:2]
print(c) # [30, 50]
{slide}
```
- Équivalent à
```python
b = [a[i] for i in range(3, 6)]
c = [a[i] for i in range(3, 6, 2)]
# rappel : équivalent à
c = []
for in range(3, 6, 2):
c.append(a[i])
{slide}
```
## Tranches en Python : raccourcis {libyli}
- Omission des indices {anim-continue}
```python
a = [0, 10, 20, 30, 40, 50, 60, 70, 80, 90]
{slide}
```
- Début et fin automatique
```python
print(a[:3]) # [0, 10, 20]
print(a[5:]) # [50, 60, 70, 80, 90]
{slide}
```
- Avec un pas
```python
print(a[:5:2]) # [0, 20, 40]
print(a[5::2]) # [50, 70, 90]
# et que le pas
print(a[::3]) # [0, 30, 60, 90]
{slide}
```
- Astuces
```python
print(a[:]) # une copie de a
# pas négatif
print(a[::-1]) # [90, 80, 70, 60, 50, 40, 30, 20, 10, 0]
print(a[::-3]) # [90, 60, 30, 0]
{slide}
```
## Indices et tranches Python : indices négatifs {libyli}
```python
a = [0, 10, 20, 30, 40, 50, 60, 70, 80, 90]
{slide}
```
- Indices à partir de la fin
```python
print(a[-1]) # 90
print(a[len(a)-1]) # 90
print(a[-3]) # 70
print(a[len(a)-3]) # 70
{slide}
```
- Marche aussi en tranches
```python
print(a[1:-1]) # 10 ... 80
print(a[1:len(a)-1]) # 10 ... 80
print(a[:-3]) # 0 ... 60
{slide}
```
# @copy:#plan: %+class:inred: .npslicing
## Numpy : indices et tranches
- Autant d'indices que de dimensions
- Pour chaque dimension, tout marche comme avec les liste
- indices
- indices négatif
- tranches
- valeurs par défaut
- indices négatifs
- pas
- pas négatif
# Re: Illustration de Numpy : $\pi$
# @copy:#plan: %+class:inred: .matplotlibintro
## Matplotlib {libyli}
- Motivation
- tracer des graphes (courbes, nuages de points, histogrammes, etc)
- gérer automatiquement l'affichage des axes, titres, graduations, etc.
- permettre éventuellement l'interaction l'utilisateur (zoom, etc.)
- permettre éventuellement de sauver des fichiers (jpg, pdf, etc.)
- Bibliothèque Matplotlib (module `matplotlib`)
- généralement `from matplotlib import pyplot as plt`
- tracé de différents types de graphes
- gestion des sous graphes
- http://matplotlib.org/
- http://matplotlib.org/gallery.html
## Matplotlib : exemple
```python
from matplotlib import pyplot as plt
x = [1, 2, 3, 9, 10]
y = [ e**3 for e in x ]
z = [ (10+e)**2 for e in x ]
plt.plot(x, y, label="courbe 1")
plt.plot(x, z, label="courbe 2")
plt.legend()
plt.savefig('courbes.pdf')
plt.show()
```
# Illustration de Numpy + Matplotlib : affichage des pas (quand on marche)
- {comment}
- np.genfromtxt(..., separator=',')
- cf prep/steps
# OK {no-print}
/ − will be replaced by the author − will be replaced by the title