Université de Bordeaux, Master Mention Informatique, 2021-2022

Analyse, classification et indexation des données: feuille 1

Rappels : Probabilités et statistiques, Algèbre linéaire avec Python

Présentation

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.

1. Vecteurs et matrices

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.

In [ ]:
import numpy as np

Exercice 1.

Création de tableaux, accès à un élément d'un tableau

Création d'un vecteur ligne :

In [ ]:
L1 = np.array([10, 20, 30, 40])
L1

Création d'un vecteur colonne :

In [ ]:
C1 = np.array([[10], [20], [30], [40]])
C1

Question : Comment obtenir C1 à partir de L1 ?

In [ ]:
C2 = L1.reshape((4, 1))
C2

Accès à un élément d'un tableau. Les indices commencent à 0.

In [ ]:
L1[2]
In [ ]:
C1[2]
In [ ]:
C1[2][0]

Création d'une matrice :

In [ ]:
M1 = np.array([[10, 20, 30], [40, 50, 60], [70, 80, 90]])
M1

La matrice est 3 x 3 :

In [ ]:
M1.shape

Taille d'une matrice, d'un vecteur, d'un tableau :

In [ ]:
np.size(L1)
In [ ]:
np.size(C1)
In [ ]:
np.size(M1)
In [ ]:
np.size(M1[1])

Accéder aux éléments d'un tableau 2D (indiceLigne, indiceColonne) :

In [ ]:
iL = 1
iC = 2
M1[iL, iC]

Extraire une ligne, une colonne :

In [ ]:
print(M1[1, :])
print(M1[:, 2])

Extraire une sous-matrice :

In [ ]:
M1[1:2, 0:1]

Fonctions prédéfinies de création de tableaux :

In [ ]:
M2 = np.zeros(3) 
M2
In [ ]:
M3 = np.zeros((1,3))
M3
In [ ]:
M4 = np.zeros((2, 3))
M4
In [ ]:
M5 = np.ones((2,4))
M5
In [ ]:
Id = np.eye(3) 
Id

Créer un tableau à partir de ses lignes :

In [ ]:
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
In [ ]:
L1 = np.array([5, 1, 3])
L2 = np.array([10, 4, 2])
M7 = np.concatenate(([L1], [L2]))
M7
In [ ]:
M8 = np.reshape(M7, (3, 2))
M8
Opérations sur les matrices

Produit scalaire de deux vecteurs :

In [ ]:
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 :

In [ ]:
L = np.linspace(0, 10, 9)
M = np.array([L, L, L])
M

Somme de deux matrices :

In [ ]:
M + M

Produit élément par élément de deux matrices :

In [ ]:
M * M

Produit de deux matrices (compatibles) :

In [ ]:
np.matmul(M, M) #erreur : pourquoi ?
In [ ]:
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 :

In [ ]:
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 :

In [ ]:
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 :

In [ ]:
L = np.linspace(0, 1000, 1000)
M = np.array([L, L, L])
In [ ]:
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 :

In [ ]:
%time P = prod_matrices(M, M.T) 
In [ ]:
%time P= np.matmul(M, M.T)

La différence est encore plus flagrante si on utilise des matrices creuses :

In [ ]:
L1 = np.linspace(0, 1000, 1000)
L2 = np.zeros(1000)
M = np.array([L2, L2, L1])
In [ ]:
%time P = prod_matrices(M, M.T) 
In [ ]:
%time P= np.matmul(M, M.T)

Exercice 2.

Chercher des éléments dans un tableau

  1. A tester :
In [ ]:
from random import sample, choices
In [ ]:
V1 = np.reshape(choices(range(1, 25), k=200), (200, ))
V1
In [ ]:
V2 = V1[V1>20]
V2
  1. Créez deux vecteurs ligne d’entiers Va et Vb, de même taille.
In [ ]:
 
  1. Testez le code suivant. Que contient V?
In [ ]:
V = np.array([Va[i] if Va[i] > Vb[i] else Vb[i] for i in range(Va.shape[0])])
V
  1. Quelle est la fonction de numpy qui permet d'obtenir le même résultat? Testez.
In [ ]:
 

2. Probabilités et statistiques, lois usuelles

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.

Loi des grands nombres

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]$.

In [ ]:
 

Essayer avec différentes valeurs $p$ et des valeurs de $n$ croissantes. Qu'observez-vous ?

In [ ]:
 

Loi normale

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 :

In [ ]:
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$.

Inférence des paramètres d'une loi normale

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.

  1. Charger les données en utilisant la fonction read_csv de la bibliothèque pandas (elle accepte les urls).
In [ ]:
 
  1. Donner une estimation de la probabilité qu'un visiteur du site (choisi au hasard) clique sur la bannière.
In [ ]:
 
  1. Le code suivant permet de tracer l'histogramme des données comme une courbe. Qu'observez-vous pour la forme de la courbe ?
In [ ]:
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='+')
  1. Calculez l'estimateur $\hat\mu$ de la moyenne et $\hat\sigma$ de la variance.

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.

In [ ]:
 
  1. Dessinez la courbe de la fonction de répartition de la loi normale de paramètres $\hat\mu$ et $\hat\sigma$ sur la même figure que celle de la question 4. Qu'observez vous ?
In [ ]: