Création de Pipelines avec Sklearn#

Mon Image

Un pipeline en machine learning est un outil structurant permettant d’automatiser et de simplifier le flux de traitement des données et de modélisation. Il consiste en une séquence ordonnée d’étapes, où chaque étape correspond à une transformation spécifique (prétraitement, sélection de caractéristiques, etc.) ou à un modèle d’apprentissage. L’objectif principal d’un pipeline est de garantir un traitement cohérent des données, depuis leur préparation jusqu’à l’entraînement et la prédiction, en minimisant le risque d’erreurs manuelles. En encapsulant toutes les étapes dans une seule entité, un pipeline favorise la réplicabilité, améliore la lisibilité du code et facilite la validation croisée sur des processus complets. Il est donc crucial en machine learning pour développer des modèles robustes et maintenables, surtout dans des environnements où la préparation des données et l’entraînement des modèles nécessitent une grande cohérence et rigueur.

Dans ce notebook, je présente tour à tour les étapes de construction d’un pipeline simple de traitement transofrmation, traitement de données.

Importation des librairies#


import numpy as np
import pandas as pd 
import matplotlib.pyplot as plt
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler, MinMaxScaler, RobustScaler, MaxAbsScaler
from sklearn.linear_model import SGDClassifier
import seaborn as sns 
from sklearn.impute import KNNImputer,SimpleImputer
from sklearn.preprocessing import (LabelEncoder, OrdinalEncoder, OneHotEncoder,
                                    LabelBinarizer, MultiLabelBinarizer)
from sklearn.compose import make_column_transformer
from sklearn.compose import make_column_selector

Separation des types de variables#

numeric = make_column_selector(dtype_include=np.number)

categorical =  make_column_selector(dtype_exclude=np.number)

Definition des transformer pour chaque type de variable#

pipe_numeric = make_pipeline(SimpleImputer(),
                             StandardScaler())

pipeline_cat = make_pipeline(SimpleImputer(strategy='most_frequent'),
                             OneHotEncoder())

Application des transformers sur chaque type de variable#

transformer_app =  make_column_transformer(
    (pipe_numeric, numeric),
    (pipeline_cat, categorical)
)

Creation du pipeline#

traitement = make_pipeline(
    transformer_app
)

Application a un jeu de données#

Vous pouvez utiliser n’importe quel jeu de données.

df = pd.read_csv('tips.csv')

y = df['total_bill']

X = df.drop('total_bill', axis=1)

traitement.fit(X, y)
Pipeline(steps=[('columntransformer',
                 ColumnTransformer(transformers=[('pipeline-1',
                                                  Pipeline(steps=[('simpleimputer',
                                                                   SimpleImputer()),
                                                                  ('standardscaler',
                                                                   StandardScaler())]),
                                                  <sklearn.compose._column_transformer.make_column_selector object at 0x00000172520E1BB0>),
                                                 ('pipeline-2',
                                                  Pipeline(steps=[('simpleimputer',
                                                                   SimpleImputer(strategy='most_frequent')),
                                                                  ('onehotencoder',
                                                                   OneHotEncoder())]),
                                                  <sklearn.compose._column_transformer.make_column_selector object at 0x0000017264881670>)]))])
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.

Data viz avec plotly#


Mon Image
# Librairies 
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go
import numpy as np

Bar plot empilées#

import plotly.graph_objects as go

# Données factices (chaque valeur est en pourcentage, donc entre 0 et 100)
years = ["2014", "2015", "2016", "2017", "2018", "2019"]
seed_angel = [60, 58, 55, 50, 40, 30]
series_a = [20, 25, 30, 35, 30, 25]
series_b = [10, 8, 7, 6, 5, 10]
series_c = [5, 5, 4, 5, 10, 15]
series_d = [3, 2, 3, 2, 5, 8]
series_e_plus = [1, 1, 1, 2, 5, 8]
other = [1, 1, 0, 0, 5, 4]

# Création du graphique avec des barres empilées
fig = go.Figure()

# Ajout des barres pour chaque étape de financement
fig.add_trace(go.Bar(name='Seed / Angel', x=years, y=[v/100 for v in seed_angel], marker_color='#4CAFDB'))
fig.add_trace(go.Bar(name='Series A', x=years, y=[v/100 for v in series_a], marker_color='#B53FA1'))
fig.add_trace(go.Bar(name='Series B', x=years, y=[v/100 for v in series_b], marker_color='#FF5C38'))
fig.add_trace(go.Bar(name='Series C', x=years, y=[v/100 for v in series_c], marker_color='#264277'))
fig.add_trace(go.Bar(name='Series D', x=years, y=[v/100 for v in series_d], marker_color='#15B399'))
fig.add_trace(go.Bar(name='Series E+', x=years, y=[v/100 for v in series_e_plus], marker_color='#F2935A'))
fig.add_trace(go.Bar(name='Other', x=years, y=[v/100 for v in other], marker_color='#D3D3D3'))

# Paramètres de mise en forme pour le mode sombre
fig.update_layout(
    barmode='stack',
    title="Part des transactions par niveau",
    xaxis_title="Années",
    yaxis_title="Pourcentage",
    yaxis=dict(tickformat=".0%", range=[0, 1]),  # Mise à jour de l'axe pour un affichage correct en pourcentage
    legend_title="Niveau de financement",
    template="plotly_dark",  # Mode sombre
    width=700,  # Largeur du graphique
    height=500  # Hauteur du graphique
)

# Affichage du graphique
fig.show()

Barplot#

# Données
data = pd.DataFrame({
    'categorie': ['A', 'B', 'A', 'C', 'B', 'A', 'A', 'B', 'C', 'A', 'B', 'C', 'B', 'A', 'C']
})

# Calcul de la fréquence et des pourcentages
frequences = data['categorie'].value_counts(normalize=True) * 100
# On replace les noms des colonnes
frequences_df = frequences.reset_index()
# On récupère les noms des colonnes
frequences_df.columns = ['categorie', 'pourcentage']
# Création du graphique en barres
fig = px.bar(frequences_df, x='categorie', y='pourcentage', text='pourcentage')
# Etiquettes de pourcentage
fig.update_traces(texttemplate='%{text:.2f}%', textposition='outside', width=0.5)
# Affichage du graphique
fig.update_layout(
    title="Répartition des catégories",
    xaxis_title="Catégorie",
    yaxis_title="Pourcentage",
    yaxis_tickformat = ",.2f",
    showlegend=False
)

# Afichage 
fig.show()
# Données
data = pd.DataFrame({
    'annee': ['2017', '2018', '2019', '2020', '2021', '2022'],
    'PIB': [2500, 2650, 2800, 2900, 3050, 3200] 
})

# Graphique en barres 
fig = px.bar(data, x='annee', y='PIB', text='PIB', color_discrete_sequence=['#003DA5'])

# Personnalisation des étiquettes
fig.update_traces(
    texttemplate='%{text:.0f} M$',  # Format des étiquettes en millions de dollars
    textposition='outside',  # Position au milieu des barres
    textfont=dict(color="black"),  # Couleur blanche pour les étiquettes
    width=0.6
)




# Configuration du layout pour le graphique
fig.update_layout(
    title="Évolution du PIB en millions de dollars (2017-2022)",
    xaxis_title="Année",
    yaxis_title="PIB (millions de dollars)",
    yaxis_tickformat=",.0f", 
    showlegend=False
)

fig.show()

Graphes avec deux axes#

# Données (précipitations, températures minimales et maximales pour chaque mois)
months = ["Jan", "Fév", "Mar", "Avr", "Mai", "Juin", "Juil", "Août", "Sept", "Oct", "Nov", "Déc"]
precipitation = [110, 100, 90, 75, 60, 50, 50, 60, 70, 90, 100, 120]  # en mm
temp_min = [20, 18, 16, 14, 11, 8, 7, 9, 12, 15, 18, 20]  # en °C
temp_max = [30, 28, 26, 23, 20, 18, 17, 20, 23, 26, 28, 30]  # en °C

# Création du graphique à barres pour les précipitations
fig = go.Figure()

fig.add_trace(go.Bar(
    x=months,
    y=precipitation,
    name="Précipitations",
    marker_color="green",
    yaxis="y2"  # On associe  l'axe des ordonnées secondaire pour les précipitations
))

# Ajout de la courbe des températures minimales
fig.add_trace(go.Scatter(
    x=months,
    y=temp_min,
    name="Température Min",
    mode="lines+markers",
    marker_color="blue",
    line=dict(width=2)
))

# Courbe pour des températures maximales
fig.add_trace(go.Scatter(
    x=months,
    y=temp_max,
    name="Température Max",
    mode="lines+markers",
    marker_color="red",
    line=dict(width=2)
))

# Mise en forme 
fig.update_layout(
    title="Graphique climatique",
    xaxis=dict(title="Mois"),
    yaxis=dict(
        title="Température (°C)",
        range=[0, 35]
    ),
    yaxis2=dict(
        title="Précipitations (mm)",
        range=[0, 175],
        overlaying="y",
        side="right"  # Positionne cet axe à droite
    ),
    legend=dict(x=0.1, y=1.1),
    template="plotly_white"
)

# Affichage
fig.show()

Graphe à barres empilées vertical#

# Données fictives
data = pd.DataFrame({
    'Niveau d\'instruction': ['Primaire', 'Primaire', 'Secondaire', 'Secondaire', 'Supérieur', 'Supérieur'],
    'Situation matrimoniale': ['Célibataire', 'Marié', 'Célibataire', 'Marié', 'Célibataire', 'Marié'],
    'Nombre': [10, 20, 15, 25, 30, 10]
})

# Calcule des pourcentages
data['Pourcentage'] = (data['Nombre'] / data.groupby('Niveau d\'instruction')['Nombre'].transform('sum') * 100).round(2)

# Création du graphique à barres empilées
fig = px.bar(data,
             x='Niveau d\'instruction',
             y='Pourcentage',
             color='Situation matrimoniale',
             text='Pourcentage',         # Pourcentages sur les barres
             title='Niveau d\'Instruction et Situation Matrimoniale',
             labels={'Pourcentage': 'Pourcentage (%)'},
             color_discrete_sequence=['#4CAF50', '#2196F3'])  # Couleurs

# Personnalisation
fig.update_traces(
    texttemplate='%{text:.2f}%',         # Format des étiquettes
    textposition='inside',               # Pourcentages à l'intérieur des barres
    textfont_color='white',              # Couleur des pourcentages
    width=0.4                            # Largeur des barres réduite
)

# Configuration du layout pour le graphique
fig.update_layout(
    yaxis_title='Pourcentage (%)',
    xaxis_title='Niveau d\'instruction',
    barmode='stack',                     # pour empiler
    template='plotly_white',
    yaxis=dict(gridcolor='LightGray'),   # Couleur de la grille
    xaxis=dict(gridcolor='LightGray')    # Couleur de la grille
)

# Affichage
fig.show()

Graphe à barres groupées#

# Données
data = pd.DataFrame({
    'Niveau d\'instruction': ['Primaire', 'Primaire', 'Secondaire', 'Secondaire', 'Supérieur', 'Supérieur'],
    'Situation matrimoniale': ['Célibataire', 'Marié', 'Célibataire', 'Marié', 'Célibataire', 'Marié'],
    'Nombre': [10, 20, 15, 25, 30, 10]
})

# Calculer des pourcentages 
data['Pourcentage'] = (data['Nombre'] / data.groupby('Niveau d\'instruction')['Nombre'].transform('sum') * 100).round(2)

# Graphique à barres groupées
fig = px.bar(data,
             x='Niveau d\'instruction',
             y='Pourcentage',
             color='Situation matrimoniale',
             text='Pourcentage',     
             title='Niveau d\'Instruction et Situation Matrimoniale',
             labels={'Pourcentage': 'Pourcentage (%)'},
             color_discrete_sequence=px.colors.qualitative.Set2)

# Personnalisation
fig.update_traces(
    texttemplate='%{text:.2f}%',     # Format des étiquettes en pourcentage avec deux chiffres après la virgule
    textposition='outside',           # Pourcentages à l'extérieur des barres
    width=0.4 
)


# Ici tu peux aussi configurer la taille du graphique
fig.update_layout(
    yaxis_title='Pourcentage (%)',
    xaxis_title='Niveau d\'instruction',
    barmode='group',  # Utilisation du mode groupé
    template='plotly_white'
)

# Affichage 
fig.show()

Graphe à barres empilées horizontal#

# Données 
data = pd.DataFrame({
    'Niveau d\'instruction': ['Primaire', 'Primaire', 'Secondaire', 'Secondaire', 'Supérieur', 'Supérieur', 'Doctorat', 'Doctorat'],
    'Situation matrimoniale': ['Célibataire', 'Marié', 'Célibataire', 'Marié', 'Célibataire', 'Marié', 'Célibataire', 'Marié'],
    'Nombre': [10, 20, 15, 25, 30, 10, 5, 5]
})

# Calcule des pourcentages
data['Pourcentage'] = (data['Nombre'] / data.groupby('Niveau d\'instruction')['Nombre'].transform('sum') * 100).round(2)

# Graphique à barres empilées horizontal
fig = px.bar(data,
             y='Niveau d\'instruction',
             x='Pourcentage',
             color='Situation matrimoniale',
             text='Pourcentage',  # Afficher les pourcentages sur les barres
             title='Répartition en Pourcentage par Niveau d\'Instruction et Situation Matrimoniale',
             labels={'Pourcentage': 'Pourcentage (%)'},
             color_discrete_sequence=['purple', '#2196F3'],  # Couleurs personnalisées : rose et bleu
             orientation='h')  # Orientation horizontale

# Personnalisation des étiquettes
fig.update_traces(
    texttemplate='%{text:.2f}%',  # Format des étiquettes en pourcentage
    textposition='inside',        # Pourcentages à l'intérieur des barres
    textfont_color='white'        # Couleur des pourcentages en blanc
)

# Configuration du layout
fig.update_layout(
    xaxis_title='Pourcentage (%)',
    yaxis_title='Niveau d\'instruction',
    barmode='stack',              # Utilisation du mode empilé
    template='plotly_white'
)

# Affichage
fig.show()

Histogramme#

# Revenus (en milliers de dollars)
np.random.seed(42)
data = pd.DataFrame({
    'revenu': np.random.normal(50, 15, 1000)       # Moyenne de 50k, écart-type de 15k
})

# Création de l'histogramme
fig = px.histogram(data, x='revenu', nbins=30,     # nombre de barres
                   title="Distribution des revenus",
                   labels={'revenu': "Revenu (en milliers de dollars)"})

# Personnalisation de l'histogramme
fig.update_layout(
    xaxis_title="Revenu (en milliers de dollars)",
    yaxis_title="Fréquence",
    bargap=0.1,                                     # Espace entre les barres
    template="plotly_white"                         # Fond blanc
)

# Affichage
fig.show()

Box-plot#

# Données
np.random.seed(42)
data = pd.DataFrame({
    'revenu': np.random.normal(50, 15, 1000)  # Moyenne de 50k, écart-type de 15k
})

# Box-plot
fig = px.box(data, y='revenu', 
              title="Box-plot des revenus individuels",
              labels={'revenu': "Revenu (en milliers de dollars)"})

# Personnalisation 
fig.update_layout(
    yaxis_title="Revenu (en milliers de dollars)",
    template="plotly_white"
)

# Affichage
fig.show()
# Données
np.random.seed(42)  # Pour la reproductibilité
n_observations = 50

# Classes du collège au lycée
classes = ['6ème', '5ème', '4ème', '3ème', 'Seconde', 'Première', 'Terminale']

# DataFrame 
data = pd.DataFrame({
    'Classe': np.random.choice(classes, n_observations),
    'Âge': np.random.randint(11, 19, n_observations)  # Âges entre 11 et 18
})

# Création du box plot
fig = px.box(data,
             x='Classe',
             y='Âge',
             title='Âges et Classes des élèves',
             labels={'Âge': 'Âge (années)', 'Classe': 'Classe'},
             color='Classe',  # Coloration par classe
             template='plotly_white')  # Utilisation d'un template blanc

# Configuration du layout
fig.update_layout(
    yaxis_title='Âge (années)',
    xaxis_title='Classe'
)

# Affichage
fig.show()

Nuage de points#

# Données
np.random.seed(42)  # Pour la reproductibilité
data = pd.DataFrame({
    'Age': np.random.randint(20, 60, size=50),  # Âge entre 20 et 60 ans
    'Revenu': np.random.randint(20000, 100000, size=50),  # Revenu entre 20 000 et 100 000
    'Situation matrimoniale': np.random.choice(['Célibataire', 'Marié', 'Divorcé'], size=50)  # Situation matrimoniale
})

# Création du nuage de points
fig = px.scatter(data, 
                 x='Age', 
                 y='Revenu', 
                 color='Situation matrimoniale',  # Couleur en fonction de la situation matrimoniale
                 size='Revenu',                   # Taille des points proportionnelle au revenu
                 hover_name=data.index,           # Pour Afficher l'index dans les info-bulles
                 title='Revenu en fonction de l\'Âge',
                 labels={'Age': 'Âge (ans)', 'Revenu': 'Revenu (en milliers de dollars)'},
                 template='plotly_white')

# Affichage 
fig.show()

Julien Bidias Assala
Ingénieur Statisticien économiste
Contacts :
LinkedIn
GitHub
Gmail