• 15 heures
  • Moyenne

Ce cours est visible gratuitement en ligne.

course.header.alt.is_video

course.header.alt.is_certifying

J'ai tout compris !

Mis à jour le 20/07/2022

TP - Mesurez la puissance des forêts aléatoires

Le fonctionnement des forêts aléatoires doit maintenant être un peu plus clair pour vous. Il est temps de passer à la pratique en observant les performances de ce type de modèle sur des données réelles 🙂

Dans ce chapitre, on va appliquer l’algorithme des forêts aléatoires sur un exemple concret. Le jeu de données que j’ai choisi est assez connu : il permet de reconnaître l’activité physique à partir de données du smartphone. Il est simple mais possède de nombreuses variables (> 500) ce qui va nous permettre d’étudier un certain nombre de choses. Prêt·e ? Affutez votre Notebook et téléchargez le nouveau dataset ici.

Le dataset

En plus de charger le dataset, vous pouvez aussi observer le fichier de description des différentes variables afin d’avoir une meilleur idée des données à disposition.

Dans un premier temps, étudions le dataset à notre disposition : le "Human Activity Recognition Using Smartphones Data Set".

Ce jeu de données contient les logs de capteurs de smartphone sur une trentaine d'individus en train d'effectuer des activités (s'assoir, se mettre debout, marcher, etc). L'objectif sera de prédire à partir des logs de capteurs le type d'activités que le sujet est en train d'effectuer.

En regardant le fichier de description du dataset, on peut observer qu'il y a beaucoup de features (561). D'emblée, en observant ce qu'elles désignent, on peut se dire qu'il y a une certaine redondance entre toutes ces variables. Dans un premier temps, on va effectuer une modélisation "brute" sans se soucier de nettoyer le jeu de données.

Dans un second temps, on va utiliser cette première modélisation pour mieux comprendre le dataset et ainsi effectuer une seconde modélisation plus efficace en éliminant des variables peu importantes.

On commence par charger les données.

import pandas as pd

train = pd.read_csv("train.csv")
test  = pd.read_csv("test.csv")

On regarde la taille des données.

print(train.shape)
(7352, 563)

Les données représentent des vecteurs de différentes mesures effectuées par le téléphone (accélération, secousses, etc). La dernière colonne représente l'activité, c'est ce qu'on va essayer de prédire à partir du reste.

Regardons tout d'abord s'il existe des valeurs manquantes :

train.isna().sum()
tBodyAcc-mean()-X 0 
tBodyAcc-mean()-Y 0 
tBodyAcc-mean()-Z 0 
tBodyAcc-std()-X 0 
tBodyAcc-std()-Y 0 .. 
angle(X,gravityMean) 1 
angle(Y,gravityMean) 1 
angle(Z,gravityMean) 1 
subject 1 
Activity 1 
Length: 563, dtype: int64

Nous allons d'abord supprimer les valeurs manquantes de la target

train = train.loc[train.Activity.notna()]

Ensuite nous allons imputer les valeurs manquantes par la médiane.

train = train.fillna(train.median(), inplace=True)

Vérifions que les données ne contiennent plus de valeurs manquantes :

train.isna().sum().sum()
0

Faites, au besoin, la même chose pour le test, et enfin séparons X et y pour le train et pour le test.

X_train = train[train.columns[:-2]]
y_train = train['Activity']

X_test = test[test.columns[:-2]]
y_test = test['Activity']

On va d'abord éliminer les features redondantes (intuitivement, les coordonnées polaires et cartésiennes doivent être corrélées par exemple ... ) Une première manière de faire serait de réfléchir et se renseigner sur le domaine d'études en question pour pouvoir éliminer des variables qui transmettent des informations similaires où n'influencent pas ou très peu la prédiction que l'on veut effectuer.

La seconde manière est d'utiliser justement une forêt aléatoire (!) de laquelle on va extraire l'importance des features qui la constituent, et ainsi déterminer quelles sont les features les plus importantes à partir de ça.

Application des forêts aléatoires

Une fois les données chargées, on peut déclarer un nouveau modèle de forêts aléatoires pour la classification logiquement appelé dans scikit   sklearn.RandomForestClassifier . On définit comme hyperparamètres 500 pour le nombre d'arbres. 

from sklearn.ensemble import RandomForestClassifier

rfc = RandomForestClassifier(n_estimators=500, oob_score=True)

On peut maintenant entraîner notre modèle sur les données brutes, sans autre forme de procès.

model = rfc.fit(X_train, y_train)

Voyons les  performances de ce modèle sur le jeu de données d'entraînement

from sklearn.metrics import accuracy_score

pred = rfc.predict(X_test)
print("accuracy {:.2f}".format(accuracy_score(y_test, pred)))
0.93

Pas mal 😎  !

Maintenant que notre modèle est créé, on peut effectuer une sélection des features les plus importantes. Pour cela on va utiliser la fonction  SelectFromModel  qui utilise la propriété du modèle qu'on vient de créer  model.feature_importances_  qui permet d'évaluer l'importance relative des features fournies à la base (sur une échelle de 0 à 1). Intuitivement, cette importance est calculée en considérant que plus une feature est haute, plus elle contribue à une fraction plus élevée du jeu de donnée d'entraînement et donc des données au global. On considère donc qu'elle a plus d'importance que les features plus bas dans l'arbre. Cette fraction est utilisée comme estimateur de l'importance de la feature dans cet arbre, qu'on peut ensuite généraliser à la forêt entière. 

Si on a peu de features, on pourrait les afficher sur un histogramme afin d'évaluer à l'œil si il n'y a pas déjà une sélection à faire comme ici.

Donc en utilisant  SelectFromModel  avec un seuil d'importance choisi à l'aide de l'argument  threshold  , on peut créer une sélection des features qui sont les plus importantes à la création d'un modèle.

from sklearn.feature_selection import SelectFromModel
select = SelectFromModel(rfc, prefit=True, threshold=0.003)
X_train2 = select.transform(X_train)
print(X_train2.shape)
(7352, 84)

On a divisé par 5 le nombre de features utilisées, pas mal mais voyons si les performances restent similaires. À l'aide de l'argument threshold, on peut choisir le seuil d'importance que l'on souhaite pour les features à sélectionner.  On calcule en même temps le gain de temps car c'est ce qui nous intéresse principalement dans l'amélioration des performances.

import timeit

rfc2 = RandomForestClassifier(n_estimators=500, oob_score=True)

start_time = timeit.default_timer()

rfc2 = rfc2.fit(X_train2, y_train)

X_test2 = select.transform(X_test)

pred = rfc2.predict(X_test2)
elapsed = timeit.default_timer() - start_time
accuracy = accuracy_score(y_test, pred)

print("accuracy {:.2f} time {:.2f}s".format(accuracy, elapsed))
accuracy 0.89 time 16.38s 

Et pour le modèle avec toutes les features

accuracy 0.93 time 50.04s

On a donc plus que divisé par trois le temps de calcul, sans trop perdre en performances ! C'est plus que respectable pour un premier jet.

Conclusion

A vous maintenant de bidouiller afin d'améliorer les performances du modèle finale en modifiant les différents hyperparamètres de contrôle et trouver la bonne balance entre performances de classification / temps de calcul. Bien sûr le ratio souhaité dépendra de la problématique : est-ce qu'on veut une très bonne performance et peu importe le temps de calcul, ou bien un temps de calcul le plus rapide possible mais avec une performance minimum etc etc

Exemple de certificat de réussite
Exemple de certificat de réussite