ANALYSE PRÉDICTIVE

Objectif

Récupération d'un jeu de données

In [1]:
from sklearn.datasets import fetch_mldata
mnist = fetch_mldata('MNIST original')
mnist
Out[1]:
{'DESCR': 'mldata.org dataset: mnist-original',
 'COL_NAMES': ['label', 'data'],
 'target': array([0., 0., 0., ..., 9., 9., 9.]),
 'data': array([[0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0],
        ...,
        [0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0]], dtype=uint8)}
In [8]:
# mnist référence un objet (jeu de données) de type dictionnaire
# La première clé décrit le jeu de données sous la forme d'une chaîne de caractères
print(type(mnist["DESCR"]))
<class 'str'>

L'ensemble des images contenue dans le jeu de données MNIST sont référencées par la clé : data du dictionnaire de type numpy.ndarray, c'est à dire tableau numpy

In [2]:
dataset = mnist["data"]
print(type(dataset))
print(dataset.shape)
<class 'numpy.ndarray'>
(70000, 784)
In [15]:
import matplotlib
import matplotlib.pyplot as plt
digit = dataset[64600]
img_digit = digit.reshape(28,28)
plt.imshow(img_digit)
plt.show()

Chaque image est accompagnée de son étiquette qui référence le chiffre réprésenté sur l'image. L'ensemble des etiquettes est contenu dans un tableau numpy de type numpy.ndarray

In [5]:
etiquettes = mnist["target"]
print(type(etiquettes))
print(etiquettes[21300])
<class 'numpy.ndarray'>
3.0

Q1 : Écrire une fonction $showDigits$ dont vous déterminerez les parèmetres permettant d'afficher sous la forme d'un tableau $[10, n]$ (avec $n\in\mathbb{N}$) l'ensemble des chiffres du jeu de données, compris entre 0 et 9, avec pour chaque chiffre n images différentes. Dans la limite bien sûr du nombre d'images disponibles pour chaque chiffre

Exemple d'un tableau $[10,10]$

Faire la disctinction entre deux classes : 8 ou pas 8 ?

Pour commencer nous allons entraîner un séparateur linéaire encore appelé classificateur binaire.

Objectif : un détecteur de 8

In [6]:
from sklearn.linear_model import SGDClassifier

img_digit_train   = dataset[:60000]     #les images pour l'entraînement
img_digit_test    = dataset[60000:]     #les images pour les tests

digit_train       = etiquettes[:60000]  #les valeurs numériques associées au images
digit_test        = etiquettes[60000:]  #idem

#import numpy as np
#shuffle_index     = np.random.permutation(60000)
#img_digit_train   = img_digit_train[shuffle_index]
#digit_train       = digit_train[shuffle_index]

digit_train_8     = (digit_train == 8)  #entraînement supervisé
digit_test_8      = (digit_test == 8)

sgd_clf = SGDClassifier(random_state=42)
sgd_clf.fit(img_digit_train, digit_train_8)
/home/c-top/anaconda3/lib/python3.6/site-packages/sklearn/linear_model/stochastic_gradient.py:128: FutureWarning: max_iter and tol parameters have been added in <class 'sklearn.linear_model.stochastic_gradient.SGDClassifier'> in 0.19. If both are left unset, they default to max_iter=5 and tol=None. If tol is not None, max_iter defaults to max_iter=1000. From 0.21, default max_iter will be 1000, and default tol will be 1e-3.
  "and default tol will be 1e-3." % type(self), FutureWarning)
Out[6]:
SGDClassifier(alpha=0.0001, average=False, class_weight=None, epsilon=0.1,
       eta0=0.0, fit_intercept=True, l1_ratio=0.15,
       learning_rate='optimal', loss='hinge', max_iter=None, n_iter=None,
       n_jobs=1, penalty='l2', power_t=0.5, random_state=42, shuffle=True,
       tol=None, verbose=0, warm_start=False)
In [7]:
any_digit         = dataset[21300]           # un 3
any_another_digit = dataset[50000]           # un 8

print(sgd_clf.predict([any_digit]))
print(sgd_clf.predict([any_another_digit]))
[False]
[ True]

Q2 : Écrire une fonction $identifyDigit(x\_train, y\_train, y\_test, digit)$ permettant à l'utilisateur de choisir le chiffre à détecter.

Q3 : Écrire une fonction $perform(sgd\_clf, dataset, start, end)$ renvoyant le nombre total des chiffres mal détectés, par exemple l'image du chiffre 4 qui n'aurait pas été détecté comme la valeur numérique 4. Que remarquez-vous ?

Tous les chiffres pour lesquels ont s'attend à une réponse positive lors de la détection ne sont pas forcément validés, il est donc nécessaire d'estimer la performance de notre classificateur.

Correction

Q1 :

In [ ]:
def showDigits(dataset, rows, columns, start_img, step):
    fig=plt.figure(figsize=(8, 8))
    pos = 1
    for row in range(0, rows):
        for col in range(0, columns):
            digit = dataset[start_img + row*step + col]
            img_digit = digit.reshape(28,28)
            fig.add_subplot(rows, columns, pos)
            plt.imshow(img_digit)
            pos += 1
    plt.show()
    
showDigits(dataset, 10, 10, 3000, 6000)

Q2 :

In [12]:
sgd_clf = SGDClassifier(random_state=42)
def identifyDigit(sgd_clf, x_train, y_train, y_test, digit):
    digit_train     = (y_train == digit)  #entraînement supervisé
    digit_test      = (y_test  == digit)
    sgd_clf.fit(x_train, digit_train)
    return sgd_clf
In [13]:
sgd_clf = identifyDigit(sgd_clf, img_digit_train, digit_train, digit_test, 4)

any_digit         = dataset[64500]           # un 4
any_another_digit = dataset[64550]           # un autre 4

print(sgd_clf.predict([any_digit]))
print(sgd_clf.predict([any_another_digit]))
/home/c-top/anaconda3/lib/python3.6/site-packages/sklearn/linear_model/stochastic_gradient.py:128: FutureWarning: max_iter and tol parameters have been added in <class 'sklearn.linear_model.stochastic_gradient.SGDClassifier'> in 0.19. If both are left unset, they default to max_iter=5 and tol=None. If tol is not None, max_iter defaults to max_iter=1000. From 0.21, default max_iter will be 1000, and default tol will be 1e-3.
  "and default tol will be 1e-3." % type(self), FutureWarning)
[ True]
[ True]

Q3 :

In [10]:
def performance(sgd_clf, dataset, start, end):
    count = 0
    for d in dataset[start:end]:
        if sgd_clf.predict([d]) == False:
            count += 1
    return count
In [14]:
performance(sgd_clf, dataset, 64500, 64600)
Out[14]:
18