TP 8 : Classification supervisée : les attributs catégoriques

Dans ce nouveau TP sur les arbres de décision, on voit comment traiter les attributs nominaux.

À l'issue de ce TP, vous m'envoyez par email un compte-rendu (format odt ou pdf) indiquant la réponse aux questions qui sont posées. Vous m'envoyez également un fichier python réalisant toutes les manipulations de ce TP. Appelez-le tp8.votre-nom.py. Je dois pouvoir exécuter ce fichier en tapant python3 tp8.votre-nom.py et reproduire vos résultats. Cette exécution ne doit pas provoquer d'erreur de python. Remarque : un notebook ne convient pas.

Attributs nominaux (ou catégoriques)

Les attributs nominaux sont faciles à traiter pour induire un arbre de décision mais malheureusement, scikit_learn ne sait pas le faire. Il faut utiliser des moyens détournés pour arriver à les prendre en compte, quoique de manière pas très satisfaisante. Comme c'est l'outil que l'on utilise, on va quand même voir comment faire avec cet outil. Mais je ne peux que vous encouragez à ne pas utiliser cette approche et à vous tourner vers un logiciel sérieux : R (ou encore c4.5). Malheureusement, nous n'avons pas le temps d'apprendre à utiliser R dans les quelques heures que dure ce module.

Principe de traitement des attributs nominaux

Nous allons illustrer le principe sur un jeu de données contenant des attributs nominaux et des attributs quantitatifs. Ce jeu de données est disponible à cette url https://philippe-preux.codeberg.page/ensg/miashs/datasets/enoughTip.csv. Je suppose par la suite que vous avez chargé ce jeu de données dans un objet dénommé tips.

Aux États-Unis (et dans d'autres pays), à moins d'être un goujat ou d'avoir été particulièrement mal traité par le serveur, on donne systématiquement un pourboire au restaurant et dans les bars. En effet, le service n'est pas inclus dans la note. En principe, ce pourboire s'élève à au moins 15% de la note.
Chaque ligne de ce jeu de données contient des informations concernant une tablée dans un restaurant :

Les attributs TOTBILL, TIP et SIZE sont numériques. Les autres attributs sont nominaux. On veut prédire l'attribut enough.
Considérons l'attribut DAY qui vaut sun, sat, fri, ou thurs. Pour pouvoir construire un arbre de décision avec scikit_learn, nous devons le transformer en un attribut numérique. La méthode que l'on va utiliser doit fonctionner quel que soit le nombre de valeurs que peut prendre l'attribut (l'arité de l'attribut). Cet attribut prenant 4 valeurs différentes, il va être transformé en 4 attributs valant 0 ou 1 : chacun de ces 4 attributs correspond donc à l'une des 4 valeurs possibles de l'attribut et 1 seul de ces 4 nouveaux attributs numériques vaudra 1.
Cela pourrait constituer un petit exercice de programmation, mais pandas dispose d'une fonction qui effectue cette transformation pour nous. Faites : pd.get_dummies(tips.DAY).head(). Cela affiche :

   fri   sat   sun   thurs 
0     0     0     1       0
1     0     0     1       0
2     0     0     1       0
3     0     0     1       0
4     0     0     1       0

alors que cet attribut vaut :
>>> tips.loc[:,"DAY"].head()
0    sun 
1    sun 
2    sun 
3    sun 
4    sun 
Name: DAY, dtype: object

On voit que la valeur d'origine de l'attribut est transformée en un data frame pandas composé de 4 colonnes, une colonne par valeur possible.
On peut regarder la fin du data frame 
>>> tips.loc[:,"DAY"].tail()
239      sat 
240      sat 
241      sat 
242      sat 
243    thurs 
Name: DAY, dtype: object

qui se transforme en  :
>>> pd.get_dummies(tips.DAY).tail()
     fri   sat   sun   thurs 
239     0     1     0       0
240     0     1     0       0
241     0     1     0       0
242     0     1     0       0
243     0     0     0       1

Maintenant que l'on sait transformer un attribut en un ensemble d'attributs numériques, il suffit d'ajouter ces 4 attributs au data frame et de retirer l'attribut nominal d'origine. Pour ajouter les colonnes, on utilise la méthode join() de pandas. Pour retirer une colonne, on utilise la méthode drop () de pandas. Cela s'utilise de la manière suivante :

>>> tips = tips.join (pd.get_dummies(tips.DAY))
tips.drop (columns = ["DAY"], inplace=True)

Remarque : visiblement, il y a un bug dans pandas. Si on a préalablement indiqué que le type de DAY est catégorique (avec tips ["DAY"] = tips ["DAY"]. astype ("category")), le join () plante, affiche une cinquantaine de lignes totalement incompréhensibles, ne me demandez pas pourquoi. Dans ce cas, il faut retirer le type catégorique de la colonne (tips ["DAY"] = tips ["DAY"]. astype ('O')) avant de faire le get_dummies().

À faire : faites ce que je viens d'expliquer et traitez de la même manière les autres attributs nominaux (SEX, SMOKER, TIME).
Remarquez que vous pouvez retirer plusieurs colonnes en une seule instruction en indiquant leur nom dans le paramètre columns de la méthode drop().

Induction d'un arbre de décision

Le data frame est maintenant utilisable par l'algorithme d'induction d'arbres de décision.

À faire : en suivant la méthode vue précédemment, induire un arbre de décision. Essayez de l'améliorer en modifiant les paramètres de l'arbre.