Analyse de données#

Dans cette feuille, nous allons mener une première analyse sur des données, afin d’obtenir une référence. Nous utiliserons d’abord les données brutes (représentation en pixel), puis nous extrairons automatiquement des attributs par Analyse en Composantes Principales.

Import des librairies#

On commence par importer les librairies dont nous aurons besoin. Comme d’habitude, nous utiliserons un fichier utilities.py où nous vous fournissons quelques fonctions et que vous complèterez au fur et à mesure du projet:

# Automatically reload code when changes are made
%load_ext autoreload
%autoreload 2
import os
from PIL import Image, ImageDraw, ImageFont
import matplotlib.pyplot as plt
%matplotlib inline
from scipy import signal
import seaborn as sns

from intro_science_donnees import *
from utilities import *

Chargement des images#

En commentant la ligne 1 ou la ligne 2, vous choisirez ici sur quel jeu de données vous travaillerez: les pommes et les bananes ou le vôtre.

dataset_dir = os.path.join(data.dir, 'ApplesAndBananas')
#dataset_dir = 'data'

images = load_images(dataset_dir, "?[012]?.png")

Nous allons aborder des jeux de données plus grands que les précédents, en nombre et en résolution des images; il faut donc être un peu prudent et parfois patient. Par exemple, le jeu de données des pommes et bananes contient plusieurs centaines d’images. Cela prendrait du temps pour les afficher et les traiter toutes dans cette feuille Jupyter. Aussi, ci-dessus, utilisons nous le glob ?[012]?.png pour ne charger que les images dont le nom fait moins de trois caractères et dont le deuxième caractère est 0, 1, ou 2.

De même, dans les exemples suivants, nous n’afficherons que les premières et dernières images :

head = images.head()
image_grid(head, titles=head.index)
tail = images.tail()
image_grid(tail, titles=tail.index)

Redimensionner et recadrer#

Comme vu au TP6, il est généralement nécessaire de redimensionner et/ou de recadrer les images. Lors du premier projet, nous avons utilisé des images recadrées pour se simplifier la tâche. Si l’objet d’intérêt est petit au milieu de l’image, il est préférable d’éliminer une partie de l’arrière-plan pour faciliter la suite de l’analyse. De même, si l’image a une résolution élevée, on peut la réduire pour accélérer les calculs sans pour autant détériorer les performances. Dans l’ensemble, les images ne doivent pas dépasser 100x100 pixels.

Dans les cellules suivantes, on recadre et redimensionne les images en 32x32 pixels. Aucun effort particulier n’est fait pour centrer l’image sur le fruit. Vous pourrez faire mieux ensuite, dans la fiche sur le prétraitement.

Dans utilities, finissez la fonction crop_image en appliquant crop à l’image.

images_cropped = images.apply(crop_image)
image_grid(images_cropped.head())

Étape 3: Représentation en pixels#

Dans les cours précédents, nous avons extrait des attributs avec des fonctions ad-hoc, comme la rougeur (redness) ou l’élongation. Les attributs ad-hoc sont pratiques pour faciliter la visualisation des données. On peut cependant obtenir d’assez bons résultats en partant directement des données brutes – ici les valeurs des pixels de nos images recadrées – et en extrayant automatiquement des attributs par décomposition en valeurs singulières, à la base de la technique de PCA. Cette analyse, présentée ci-dessous est simple à mettre en œuvre et peut donner une première base de résultats.

Vous trouverez dans utilities.py une fonction appelée image_to_series qui transforme une image en une série unidimensionnelle contenant les valeurs de tous les pixels de l’image.

show_source(image_to_series)

Exercice

Appliquez cette fonction à toutes les images, et affectez le résultat à df qui est donc un tableau de données où chaque ligne correspond à une image:

# VOTRE CODE ICI
raise NotImplementedError()
df

Exercice

Pouvez-vous expliquer le nombre de colonnes que nous obtenons?

VOTRE RÉPONSE ICI

Nous rajoutons à notre tableau de données une colonne contenant l’étiquette (ground truth) de chaque image; dans le jeu de données fourni, ce sera 1 pour une pomme et -1 pour une banane:

df['étiquette'] = df.index.map(lambda name: 1 if name[0] == 'a' else -1)
df

Exercice

Affichez les statistiques descriptives de Pandas sur votre base de données. Peut-on interpréter ces statistiques?

# VOTRE CODE ICI
raise NotImplementedError()

Sauvegarde intermédiaire#

Nous allons sauvegarder ces données brutes dans un fichier:

df.to_csv('crop_data.csv')

Cela vous permettra par la suite de reprendre la feuille à partir d’ici, sans avoir à reexécuter tous les traitements depuis le début.

Vous serez amenée à faire d’autres sauvergades intermédiaires dans votre projet.

Exercice

Chargez la table crop_data.csv dans df avec la fonction read_csv de pandas et en ajoutant l’option index_col=0 pour correctement afficher le nom des colonnes:

# VOTRE CODE ICI
raise NotImplementedError()
df

[VI]sualisation des données brutes par carte thermique#

Les données de la représentation en pixels sont volumineuses; par principe il faut tout de même essayer de les visualiser. On peut pour cela utiliser une carte thermique avec Seaborn.

plt.figure(figsize=(20,20))
sns.heatmap(df, cmap="YlGnBu");

Comme vous le constatez, les données ne sont pas aléatoires: il y a des corrélations entre les lignes. Cela reste cependant difficilement exploitable visuellement.

Étape 4: Performance de [RÉ]férence#

À présent, vous allez appliquer la méthode des plus proches voisins sur la représentation en pixels pour avoir une performance de référence.

Exercice

Déclarez le modèle sklearn_model comme un classifieur par plus proche voisin (KNN) avec 3 voisins, depuis la librairie scikit-learn.

from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import balanced_accuracy_score as sklearn_metric
# VOTRE CODE ICI
raise NotImplementedError()

Comme dans les séances précédentes, on calcule la performance et les barres d’erreurs du classifieur par validation croisée (cross validate), en divisant de multiples fois nos données en ensemble d’entraînement et en ensemble de test.

Exercice

Finissez de remplir la fonction df_cross_validate d”utilities.py afin qu’elle automatise tout le processus. Il y a deux endroits (et 3 lignes) où il y a du code manquant. Consultez son code pour retrouver les étapes:

show_source(df_cross_validate)
p_tr, s_tr, p_te, s_te = df_cross_validate(df, sklearn_model, sklearn_metric, verbose=True)

On a obtenu cette performance en comparant nos images pixel à pixel (distance euclidienne), sans aucun attribut.

Exercice

Est-ce que ce score vous semble particulièrement bon, mauvais et/ou étonnant?

VOTRE RÉPONSE ICI

Conclusion#

Cette première feuille vous fait passer par le formatage de base des données. Prenez ici quelques notes sur ce que vous avez appris, observé, interprété.

VOTRE RÉPONSE ICI

Les feuilles suivantes aborderont d’autres aspects de l’analyse (attributs, classifieur) en se basant sur des attributs que vous calculerez. Vous pourrez comparer les méthodes et appliquer celle qui vous semble la plus pertinente à votre jeu de données. Ouvrez la feuille sur l”extraction d’attributs.