L’objectif de ce premier TD est de rassembler les outils et bibliothèques Python
nécessaires pour la suite. Vous travaillerez dans le fichier td01.ipynb en ajoutant les instructions à tester et le code à écrire, ainsi que tous les commentaires qui vous permettront d'utiliser efficacement ces outils dans les TD suivants.
Pour éditer/exécuter les tests, lancez jupyter notebook
en ligne de commande puis ouvrez td01.ipynb
.
Le code est écrit dans une suite de cellules. Pour ajouter une cellule utilisez l'item Insérer du menu.
Pour exécuter les instructions d'une cellule, il suffit de placer le curseur dans la cellule souhaitée et d'exécuter la cellule (en cliquant sur Exécuter
ou avec Ctrl + Return
).
Remarque : le choix a été fait de travailler sur des jupyter notebooks
mais vous pouvez tout à fait utiliser votre IDE préféré pour écrire/exécuter vos instructions et vos programmes Python
.
Un élément unique, un vecteur ligne ou colonne sont des cas particuliers de matrice (tableau 2D).
Une des bibliothèques de Python
les plus utilisées en algèbre linéaire est la bibliothèque numpy
. On commence par l'importer pour pouvoir l'utiliser pour la suite.
import numpy as np
Création de tableaux, accès à un élément d'un tableau
Création d'un vecteur ligne :
L1 = np.array([10, 20, 30, 40])
L1
Création d'un vecteur colonne :
C1 = np.array([[10], [20], [30], [40]])
C1
Question : Comment obtenir C1
à partir de L1
?
C2 = L1.reshape((4, 1))
C2
Accès à un élément d'un tableau. Les indices commencent à 0
.
L1[2]
C1[2]
C1[2][0]
Création d'une matrice :
M1 = np.array([[10, 20, 30], [40, 50, 60], [70, 80, 90]])
M1
La matrice est 3 x 3
:
M1.shape
Taille d'une matrice, d'un vecteur, d'un tableau :
np.size(L1)
np.size(C1)
np.size(M1)
np.size(M1[1])
Accéder aux éléments d'un tableau 2D (indiceLigne, indiceColonne) :
iL = 1
iC = 2
M1[iL, iC]
Extraire une ligne, une colonne :
print(M1[1, :])
print(M1[:, 2])
Extraire une sous-matrice :
M1[1:2, 0:1]
Fonctions prédéfinies de création de tableaux :
M2 = np.zeros(3)
M2
M3 = np.zeros((1,3))
M3
M4 = np.zeros((2, 3))
M4
M5 = np.ones((2,4))
M5
Id = np.eye(3)
Id
Créer un tableau à partir de ses lignes :
L1 = np.array([5, 1, 3])
L2 = np.array([10, 4, 2])
L3 = np.array([3, 5, 0])
M6 = np.concatenate(([L1], [L2], [L3]))
M6
Redimensionner une matrice :
- le nombre d'élements est le même avant et après
- le parcours ligne par ligne donne la même suite d'éléments
L1 = np.array([5, 1, 3])
L2 = np.array([10, 4, 2])
M7 = np.concatenate(([L1], [L2]))
M7
M8 = np.reshape(M7, (3, 2))
M8
Produit scalaire de deux vecteurs :
L1 = np.array([1, 2, 3])
L2 = np.array([1, 2, 3])
prod = np.dot(L1, L2)
prod
Soit M
la matrice définie comme suit :
L = np.linspace(0, 10, 9)
M = np.array([L, L, L])
M
Somme de deux matrices :
M + M
Produit élément par élément de deux matrices :
M * M
Produit de deux matrices (compatibles) :
np.matmul(M, M) #erreur : pourquoi ?
np.matmul(M, M.T)
A présent, nous allons illustrer la puissance de le bibliothèque numpy
. Pour cela nous allons d'abord définir notre propre fonction prod_matrices
calculant le produit en utilisant des boucles imbriquées :
def prod_matrices(M1, M2):
M = np.zeros((M1.shape[0], M2.shape[1]))
for i in range(M1.shape[0]):
for j in range(M2.shape[1]):
for k in range(M1.shape[1]):
M[i, j] += M1[i, k] * M2[k,j]
return M
Test de la fonction :
M1 = np.array([[2, 1, 1], [4, 5, 7]])
M2 = np.array([[3, 2], [2, 1], [5, 4]])
prod_matrices(M1, M2)
Avec un peu plus d'éléments :
L = np.linspace(0, 1000, 1000)
M = np.array([L, L, L])
P = prod_matrices(M, M.T)
P
La fonction time
permet d'afficher des statistiques sur le temps d'exécution d'une instruction Python
. Exécutez les instructions suivantes et observez les résultats :
%time P = prod_matrices(M, M.T)
%time P= np.matmul(M, M.T)
La différence est encore plus flagrante si on utilise des matrices creuses :
L1 = np.linspace(0, 1000, 1000)
L2 = np.zeros(1000)
M = np.array([L2, L2, L1])
%time P = prod_matrices(M, M.T)
%time P= np.matmul(M, M.T)
Chercher des éléments dans un tableau
from random import sample, choices
V1 = np.reshape(choices(range(1, 25), k=200), (200, ))
V1
V2 = V1[V1>20]
V2
Va
et Vb
, de même taille.
V
?V = np.array([Va[i] if Va[i] > Vb[i] else Vb[i] for i in range(Va.shape[0])])
V
numpy
qui permet d'obtenir le même résultat? Testez.
Dans cette section, nous allons passer en revue quelques éléments de probabilités et statistiques. Nous allons essentiellement faire de l'inférence statistique et manipuler la loi normale.
On lance un dé biasé. On obtient pile avec probabilité $p\in[0, 1]$ et face avec probabilité $q = 1 - p$.
Ecrire une fonction lancer(n, p)
qui simule le lancer de ce dé n
fois avec la probabilité p
d'obtenir pile et qui retourne le nombre de fois où pile est obtenu.
Indication : uniform(0,1)
de la bibliothèque random
retourne un nombre réel aléatoire tiré uniformément dans l'intervalle $[0, 1]$.
Essayer avec différentes valeurs $p$ et des valeurs de $n$ croissantes. Qu'observez-vous ?
La loi normale est très utilisée en statistiques. Elle est, entre autre, la loi limite pour d'autres lois.
Commençons par générer des nombres suivant une loi normale mais avec différentes valeurs pour les paramètres $\mu$ et $\sigma$.
Exécutez la cellule suivante et observez le résultat :
from scipy.stats import norm
import matplotlib.pyplot as plt
%matplotlib inline
mu = [0, 1, 2, 3]
sigma = [1, 2, 3, 4]
x_min = -16
x_max = 16
x_nb = 100
x = np.linspace(x_min, x_max, x_nb)
for i in range(len(mu)):
y = norm.pdf(x, mu[i], sigma[i])
plt.plot(x, y, label='mu='+str(mu[i])+', sigma='+str(sigma[i]))
plt.legend(loc='upper right')
plt.show()
Commentez les courbes et observez l'impact des valeurs de $\sigma$.
On insère une bannière publicitaire dans une page web. On trace les connexions à cette page auprès de $50$ utilisateurs et ce pendant $1000$ jours. Pour chaque visite on note si l'utilisateur a cliqué sur la bannière ou non.
Les chiffres des clics (par jour) sont donnés dans le fichier baniere.csv
disponible à l'adresse https://www.labri.fr/perso/zemmari/datasets/baniere.csv.
read_csv
de la bibliothèque pandas
(elle accepte les urls).
from collections import Counter
compteur = Counter(list(data[0]))
#print(compteur)
x = list(compteur.keys())
print(x)
y = [compteur[x[i]] for i in range(len(x)) ]
print(y)
plt.scatter(x, y, c='red', marker='+')
Indication : des estimateurs non biaisés de la moyenne et de la variance d'une série $(x_i)_{1\leq i\leq n}$ sont donnés par :
$$
\hat\mu = \frac 1 n \sum_{i=1}^n x_i, \,\,\,\, \hat\sigma^2 = \frac 1 {n} \sum_{i=1}^n \left(x_i - \hat\mu\right)^2.
$$
On peut néanmoins utiliser directement les fonctions average
et std
de la bibliothèque numpy
.