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.