columntransformer-python

Traiter différents types de colonnes avec scikit-learn et ColumnTransformer

Emmanuel Jakobowicz Mis à jour le : 30 novembre 2019 méthode Laissez un commentaire

Dans cet article, je vous présente un outil extrêmement utile pour vos modèles de machine learning sur des données structurées. Il s’agit de la classe ColumnTransformer de scikit-learn.

La construction d’un modèle de machine learning fonctionne assez simplement avec des étapes de features ingeeniring et des étapes de modélisation. L’étape de préparation des données est une étape clé. En Python, on a souvent deux approches :

  • Effectuer les préparations avec le package pandas sur des DataFrame
  • Effectuer les préparations avec les outils de preprocessing de scikit-learn.

Une limite bien souvent rencontré lorsqu’on essaye d’intégrer la préparation des données dans scikit-learn est lié à la variété des prétraitements nécessaires.

En effet, vous avez souvent dans une table de données structurées des colonnes avec des variables qualitatives et d’autres avec des variables quantitatives. Vous pouvez aussi rencontrer des cas où vous voulez varier les types de prétraitements en fonction des colonnes (standardisation de certaines colonnes, centrage pour d’autres…). Pour réussir à effectuer toutes ces actions dans un seul objet, vous devrez utiliser la classe ColumnTransformer.

L’objectif de notre modèle de machine learning est de créer un système totalement intégré dans un objet, cet objet est en général issu d’une classe spécifique : le Pipeline. L’objet de cet article n’est pas de parler des pipelines mais d’une autre outil extrêmement pratique pour des données variées, la classe ColumnTransformer.

scikit-learn

Fonctionnement de ColumnTransformer

L’idée qui se cache derrière la classe ColumnTransformer est de permettre de traiter simultanément toutes les transformations nécessaires sur notre jeu de données.

Prenons un exemple simple d’analyse de l’attrition des clients, nous allons dérouler l’analyse et le traitement de ces données.

On commence par importer les outils nécessaires :

import numpy as np
import pandas as pd
# il s'agit de la classe qui nous intéresse
from sklearn.compose import ColumnTransformer

# on utilisera un pipeline pour enchaîner les traitements
from sklearn.pipeline import Pipeline

# les méthodes de prétraitement
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import StandardScaler, OneHotEncoder

# les outils de machine learning
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split

On importe ensuite les données :

churn = pd.read_csv("./churn.csv")

Une fois les données importées, on peut détailler leur contenu :

Il s’agit d’une colonne churn qui indique si le client a renouvelé son abonnement et des colonnes liées à la consommation de ce client.

Nous nous intéresserons à 6 colonnes :

  • des colonnes qualitatives, dans ce cas, nous devrons appliquer :
    • Un traitement des données manquantes ajoutant une modalité « manquant »
    • Une transformation OneHot ce qui veut dire qu’on va créer une colonne binaire par modalité de la colonne (il s’agit d’un tableau disjonctif complet)
  • des colonnes quantitatives, dans ce cas, nous devons appliquer :
    • Un traitement des données manquantes en remplaçant par la médiane
    • Une standardisation des données (transformation de manière à ce que la moyenne soit 0 et la variance 1)

En terme de code, nous allons créer des pipelines de transformation pour chaque type de colonnes et inclure cela dans un objet de la classe ColumnTransformer :

# on définit les colonnes et les transformations pour 
# les colonnes quantitatives
col_quanti = ['Day Mins', 'Day Calls', 'Day Charge',
       'Eve Mins', 'Eve Calls', 'Eve Charge', 'Night Mins', 'Night Calls',
       'Night Charge', 'Intl Mins', 'Intl Calls', 'Intl Charge',
       'CustServ Calls']

transfo_quanti = Pipeline(steps=[
    ('imputation', SimpleImputer(strategy='median')),
    ('standard', StandardScaler())])

# on définit les colonnes et les transformations pour
# les variables qualitatives
col_quali = ['Area Code', "Int'l Plan", 'VMail Plan']

transfo_quali = Pipeline(steps=[
    ('imputation', SimpleImputer(strategy='constant', fill_value='manquant')),
    ('onehot', OneHotEncoder(handle_unknown='ignore'))])

# on définit l'objet de la classe ColumnTransformer
# qui va permettre d'appliquer toutes les étapes
preparation = ColumnTransformer(
    transformers=[
        ('quanti', transfo_quanti , col_quanti),
        ('quali', transfo_quali , col_quali)])

On a ainsi construit un objet preparation qui combine les étapes de transformation des différentes colonnes de notre jeu de données.

On a maintenant deux possibilités, soit on désire appliquer ces transformation afin de créer un nouvel objet, il s’agira d’un array, soit on veut construire un processus de traitement machine learning (ce qui est généralement le cas).

Créer un jeu de données transformé

On peut utiliser :

churn_transfo = preparation.fit_transform(churn)

On a ainsi appliqué les transformations sur nos données initiales. L’objet preparation conserve les informations liées aux transformations.

Intégrer la transformation dans un pipeline de machine learning

On peut maintenant lancer notre modèle de machine learning (dans ce cas une régression logistique) en utilisant un pipeline :

# on crée un pipeline de traitement intégrant la préparation
modele_ml = Pipeline(steps=[('preparation', preparation),
                      ('logit', LogisticRegression(solver='lbfgs'))])

# on sépare la cible du reste des données
x = churn.drop('Churn?', axis=1)
y = churn['Churn?']

# on construit les échantillons d'apprentissage et de validation
x_train, x_test, y_train, y_test = train_test_split(x, y)

# on ajuste le modèle en utilisant les données d'apprentissage
# le modèle comporte la préparation et le modèle logistique
modele_ml.fit(x_train, y_train)

# on affiche le résultat du modèle sur les données de validation
print("Score du modèle : %.2f" % modele_ml.score(x_test, y_test))

Score du modèle : 0.86

La classe ColumnTransformer nous a donc permis de simplifier notre processus de traitement de manière radical.

Aller plus loin : les hyper-paramètres

L’objet modele_ml étant de la classe Pipeline, nous pouvons travailler dessus pour effectuer de nombreuses étapes de notre ajustement de modèle, notamment l’ajustement des hyper-paramètres du modèle avec une grille (grid search). L’avantage réside ici dans la possibilité de faire varier les hyper-paramètres des méthodes de prétraitement. En voici un exemple :

from sklearn.model_selection import GridSearchCV

# on définit les paramètres à faire varier
param_grid = {
    'preparation__quanti__imputation__strategy': ['mean', 'median'],
    'logit__C': [0.1, 1.0, 10, 100] }

# on crée le modèle de grille
grid_search = GridSearchCV(modele_ml, param_grid, cv=5)
# on ajuste aux données d'apprentissage
grid_search.fit(x_train, y_train)


print(("Le meilleur modèle logistique obtenu a comme performance : %.2f"
       % grid_search.score(x_test, y_test)))

Le meilleur modèle logistique obtenu a comme performance : 0.86

On a ainsi testé différentes combinaison de modèles afin d’obtenir le plus efficace. Cette approche nous permet de créer un seul objet modele_ml qui va être extrêmement puissant. De plus son utilisation en production va faciliter les automatisations.

Plus de détails sur la classe ColumnTransformer :

Nos formations Python pour monter en compétence et découvrir le langage Python pour la data

Partager cet article

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.