Par Maxime Jumelle
CTO & Co-Founder
Publié le 27 nov. 2020
Catégorie Machine Learning
Dans la plupart des projets de Machine Learning, le jeu de données utilisé pour calibrer le modèle doit subir toute une série de transformations. Encodage de variables catégorielles, de la normalisation, du feature scaling et autres techniques spécifiques.
Cependant, cette série de transformations doit être appliquée plus d'une fois. D'une part, au moment où il faut entraîner le modèle, et d'autre part lorsqu'il faut obtenir une prédiction pour de nouvelles données. Comment ne pas mélanger les différentes étapes et garantir un traitement consistant entre ces deux étapes ? C'est tout l'intérêt des pipelines de scikit-learn. Ces pipelines vont résoudre un certain nombre de problèmes.
Pour illustrer les pipelines de scikit-learn, nous allons utiliser le jeu de données suivant.
import pandas as pd dataset = pd.read_csv( "https://dv495y1g0kef5.cloudfront.net/single_notebooks/data/car_acc.csv", header=0, names=["buying", "maint", "doors", "persons", "lug_boot", "safety", "eval"] ) dataset.head()
Chaque ligne représente une voiture. Les variables explicatives sont :
buying
(qualitative) : un prix d’achat (bas, moyen, haut et très
haut).maint
(qualitative) : entretien nécessaire pour le fonctionnement
(bas, moyen, haut et très haut).doors
(quantitative) : le nombre de portes.persons
(quantitative) : le nombre de personnes.lug_boot
(qualitative) : la taille du coffre (petit, moyen et grand).safety
(qualitative) : le niveau de sécurité (faible, modéré et fort).La variable que l’on souhaite modéliser (i.e. la variable réponse) est
nommée eval
et représente le niveau de satisfaction de la voiture (unacc pour non satisfait ou acc pour satisfait).
Un Transformer est un objet scikit-learn
qui permet d'appliquer une transformation (encodage, normalisation, ...) sur un DataFrame. L'intérêt du Transformer est double.
À lire aussi : découvrez notre formation MLOps
Nous allons commencer par encoder les colonnes lug_boot
et safety
en one-hot avec le OneHotEncoder
.
from sklearn.pipeline import Pipeline from sklearn.preprocessing import OneHotEncoder one_hot_encoder = Pipeline( steps=[ ('one_hot', OneHotEncoder(handle_unknown='ignore')) ] )
ℹ️ Pas besoin de définir pour l'instant les colonnes qui vont subir cette transformation : cela sera effectué lorsque l'on assemblera les Transformers.
Nous pouvons également construire un Transformer sur mesure avec FunctionTransformer
. En particulier, nous allons construire un Transformer pour certaines variables explicatives pour lesquelles nous considérons qu'il n'est pas nécessaire d'utiliser un OneHotEncoder
. Les colonnes buying
et maint
prendront comme valeur 0, 1, 2 ou 3 (correspondant à low, med, high et vhigh).
from sklearn.preprocessing import FunctionTransformer encoding = { "low": 0, "med": 1, "high": 2, "vhigh": 3 } def grad_encoder(df): for col in df.columns: df[col] = df[col].apply(lambda x: encoding[x]) return df eval_encoder = Pipeline( steps=[ ('grad', FunctionTransformer(grad_encoder)) ] )
Enfin, il y a quelques cas particuliers pour les colonnes doors
et persons
: la valeur 5more est présente dans la colonne doors
s'il y a 5 portes ou plus, et de même dans la colonne persons
lorsque le véhivule peut accueillir 6 passagers ou plus.
Dans ce cas, puisque nous souhaitons uniquement des valeurs numériques dans ces colonnes, nous allons construire un dernier Transformer pour encoder ces variables.
def num_encoder(df): for col in df.columns: df[col] = df[col].apply(lambda x: 5 if x == "5more" else x) df[col] = df[col].apply(lambda x: 6 if x == "more" else x) return df num_encoder = Pipeline( steps=[ ('num', FunctionTransformer(num_encoder)) ] )
Une fois terminé, il ne reste plus qu'à combiner tous ces Transformers dans un ColumnTransformer
: cela va permettre d'appliquer chaque Transformer sur un ensemble de colonnes sur-mesure. Plutôt que d'écrire un Transformer par colonne, cela permet de gagner du temps en appliquant la même méthode d'encodage sur plusieurs colonnes.
from sklearn.compose import ColumnTransformer preprocessor = ColumnTransformer( transformers=[ ('categorical', one_hot_encoder, ['lug_boot', 'safety']), ('grad', eval_encoder, ['buying', 'maint']), ('num', num_encoder, ['doors', 'persons']), ] )
Par ailleurs, la documentation de scikit-learn présente une liste exhaustive des Transformers disponibles par défaut.
Une fois que le pipeline de preprocessing est en place, nous pouvons ajouter la couche prédictive, qui ici est un Random Forest.
À lire aussi : découvrez notre formation MLOps
from sklearn.ensemble import RandomForestClassifier rf = Pipeline( steps=[ ('preprocessor', preprocessor), ('classifier', RandomForestClassifier()) ] )
La particularité, c'est que la variable rf
n'est pas uniquement le modèle, mais renferme également les étapes de preprocessing que nous appliquons aux données.
Ainsi, qu'il s'agisse d'un fit
ou d'un predict
, les données subiront les étapes du preprocessing au préalable.
Comme toujours, nous séparons le jeu de données en un ensemble d'entraînement et un ensemble de test.
from sklearn.model_selection import train_test_split X = dataset.drop('eval', axis=1) y = dataset['eval'].apply(lambda x: 0 if x == "unacc" else 1) X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=24)
Puis nous calibrons directement le pipeline contenant le preprocessing et le modèle.
rf.fit(X_train, y_train)
Si maintenant, on souhaite calculer un score, même principe, la fonction predict
appliquera toutes les transformations au DataFrame renseigné.
from sklearn.metrics import f1_score y_pred = rf.predict(X_test) print("Score : {:2.1f}%".format(f1_score(y_test, y_pred) * 100))
L'intérêt des pipelines, en plus de la reproductibilité, est la modularité offerte par la combinaison linéaire des étapes. Par exemple, plutôt que d'avoir un seul modèle, nous souhaitons tester plusieurs modèles : il suffit juste de modifier la couche de classification, sans modifier le preprocessing.
Par exemple, ici, nous allons calibrer trois modèles : un Random Forest, un Gradient Boosting et un modèle binomial. Tous les trois auront le même jeu de données en entrée, ce qui permettra de les comparer plsu efficacement.
from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier from sklearn.linear_model import LogisticRegression models_names = ["Random Forest", "Gradient Boosting", "Logistic Regression"] # Contient les trois pipelines (une pour chaque modèle) pipelines = [ Pipeline(steps=[('preprocessor', preprocessor), ('classifier', RandomForestClassifier())]), Pipeline(steps=[('preprocessor', preprocessor), ('classifier', GradientBoostingClassifier())]), Pipeline(steps=[('preprocessor', preprocessor), ('classifier', LogisticRegression())]) ]
Nous pouvons ensuite appeler chaque pipeline.
for p, name in zip(pipelines, models_names): p.fit(X_train, y_train) y_pred = p.predict(X_test) print("Score ({}) : {:2.1f}%".format( name, f1_score(y_test, y_pred) * 100 ))
Nous vons directement ici que les deux premiers modèles sont bien meilleurs que le dernier. On pourrait ainsi imaginer la même technique si l'on effectuait une recherche par grille pour optimiser les hyper-paramètres.
Vous souhaitez vous former au MLOps ?
Dans cet article
Articles similaires
20 sept. 2022
Hugging Face est une startup française qui s'est fait connaître grâce à l'infrastructure NLP qu'ils ont développée. Aujourd'hui, elle est sur le point de révolutionner le domaine du Machine Learning et traitement automatique du langage naturel. Dans cet article, nous allons présenter Hugging Face et détailler les taches de base que cette librairie permet de réaliser. Nous allons également énumérer ses avantages et ses alternatifs.
Équipe Blent
Data Scientist
Lire l'article
12 juil. 2022
spaCy est une bibliothèque open-source pour le traitement avancé du langage naturel. Elle est conçue spécifiquement pour une utilisation en production et permet de construire des applications qui traitent et comprennent de grands volumes de texte.
Équipe Blent
Data Scientist
Lire l'article
4 juil. 2022
Un auto-encodeur est une structure de réseaux neuronaux profonds qui s'entraîne pour réduire la quantité de données nécessaires pour représenter une donnée d'entrée. Ils sont couramment utilisés en apprentissage automatique pour effectuer des tâches de compression de données, d'apprentissage de représentations et de détection de motifs.
Équipe Blent
Data Scientist
Lire l'article
60 rue François 1er
75008 Paris
Blent est une plateforme 100% en ligne pour se former aux métiers Tech & Data.
Organisme de formation n°11755985075.
Data Engineering
IA Générative
MLOps
Cloud & DevOps
À propos
Gestion des cookies
© 2024 Blent.ai | Tous droits réservés