2023-06-20 12:07:47 +02:00
import time
import numpy as np
import sklearn
2023-06-22 03:14:37 +02:00
from sklearn . linear_model import LogisticRegression
from sklearn import datasets
2023-06-20 12:07:47 +02:00
import matplotlib . pyplot as plt
2023-06-22 03:14:37 +02:00
from matplotlib . colors import ListedColormap
2023-06-20 12:07:47 +02:00
###############################################################################
# 06-regression_logistique.py
2023-06-24 09:13:47 +02:00
# @title: Fondamentaux - Apprentissage par régression logistique
2023-06-20 12:07:47 +02:00
# @project: Mes scripts de ML
# @lang: fr
# @authors: Philippe Roy <philippe.roy@ac-grenoble.fr>
# @copyright: Copyright (C) 2023 Philippe Roy
# @license: GNU GPL
###############################################################################
###
# Commandes NumPy :
# - np.array : créer un tableau à partir d'une liste de listes
2023-06-24 09:27:52 +02:00
# - np.c_ : concatène les colonnes des tableaux
2023-06-20 12:07:47 +02:00
# - np.linspace : créer un tableau 1D de la valeur de début à la valeur de fin avec n valeurs
2023-06-22 03:14:37 +02:00
# - np.meshgrid : créer un tableau 2D avec l'ensemble des combinaisons allant des deux valeurs de début aux deux valeurs de fin
2023-06-20 12:07:47 +02:00
# - .reshape : reformater la tableau avec le nombre de lignes et le nombre de colonnes
###
###
# Commandes Scikit-Learn :
2023-06-22 03:14:37 +02:00
# - sklearn.linear_model.LogisticRegression : créer un modèle de régression logistique
2023-06-22 03:21:11 +02:00
# - sklearn.linear_model.LogisticRegression(multi_class="multinomial", solver="lbfgs", C=10) : créer un modèle de régression logistique multi-classes du type Softmax
2023-06-20 12:07:47 +02:00
# - .fit : entrainement du modèle
# - .predict : prédiction du modèle
###
###############################################################################
# Initialisation
###############################################################################
# Init du temps
t_debut = time . time ( )
# Init des plots
fig = plt . figure ( figsize = ( 15 , 5 ) )
2023-06-22 03:16:33 +02:00
fig . suptitle ( " Classificateur par régression logistique " )
2023-06-22 03:14:37 +02:00
donnees1_ax = fig . add_subplot ( 131 ) # Observations : x1 et cibles : y1
donnees2_ax = fig . add_subplot ( 132 ) # Observations : x1, x2 et cibles : y11 (type de marque)
donnees3_ax = fig . add_subplot ( 133 ) # Observations : x1, x2 et cibles : y (type de marque)
2023-06-20 12:07:47 +02:00
###############################################################################
# Observations
###############################################################################
2023-06-22 03:14:37 +02:00
# Observations d'apprentisage
2023-06-20 12:07:47 +02:00
iris = sklearn . datasets . load_iris ( ) # Jeu de données Iris
2023-06-22 03:14:37 +02:00
x1 = iris [ ' data ' ] [ : , 2 ] . reshape ( - 1 , 1 ) # Longueur de pétale
x2 = iris [ ' data ' ] [ : , 3 ] . reshape ( - 1 , 1 ) # Largeur de pétale
X = iris [ ' data ' ] [ : , ( 2 , 3 ) ] # Matrice de données
y1 = ( iris [ " target " ] == 2 ) . astype ( np . int32 ) # Si Iris virginica -> 1 sinon -> 0
y = ( iris [ " target " ] ) # Type d'Iris
# Plot x1,y1 (largeur de pétale, probabilité d'être Iris virginica)
donnees1_ax . plot ( x2 [ y1 == 1 ] , y1 [ y1 == 1 ] , " g^ " , label = " Iris virginica " )
donnees1_ax . plot ( x2 [ y1 == 0 ] , y1 [ y1 == 0 ] , " rs " , label = " Iris non-virginica " )
# Plot x1,x2 et y1 (longeur de pétale, largeur de pétale et probabilité d'être Iris virginica (format de la marque))
donnees2_ax . plot ( x1 [ y1 == 1 ] , x2 [ y1 == 1 ] , " g^ " , label = " Iris virginica " )
donnees2_ax . plot ( x1 [ y1 == 0 ] , x2 [ y1 == 0 ] , " rs " , label = " Iris non-virginica " )
# Plot x1,x2 et y (longeur de pétale, largeur de pétale et type de Iris (format de la marque))
donnees3_ax . plot ( x1 [ y == 0 ] , x2 [ y == 0 ] , " yo " , label = " Iris setosa (0) " )
donnees3_ax . plot ( x1 [ y == 1 ] , x2 [ y == 1 ] , " bs " , label = " Iris versicolor (1) " )
donnees3_ax . plot ( x1 [ y == 2 ] , x2 [ y == 2 ] , " g^ " , label = " Iris virginica (2) " )
2023-06-20 12:07:47 +02:00
# Nouvelles observations
2023-06-22 03:14:37 +02:00
x1_new = np . linspace ( 0 , 8 , 1000 ) . reshape ( - 1 , 1 )
x2_new = np . linspace ( 0 , 3.5 , 1000 ) . reshape ( - 1 , 1 )
x1_new_mg , x2_new_mg = np . meshgrid ( x1_new , x2_new )
X_new = np . c_ [ x1_new_mg . ravel ( ) , x2_new_mg . ravel ( ) ]
2023-06-20 12:07:47 +02:00
###############################################################################
# Phase d'apprentissage
###############################################################################
2023-06-22 03:14:37 +02:00
model_1d = sklearn . linear_model . LogisticRegression ( ) # Modèle régression logistique
model_1d . fit ( x2 , y1 ) # Entrainement
model_2d = sklearn . linear_model . LogisticRegression ( ) # Modèle régression logistique
model_2d . fit ( X , y1 ) # Entrainement
model = LogisticRegression ( multi_class = " multinomial " , solver = " lbfgs " , C = 10 ) # Modèle régression logistique du type Softmax (multi-classes, multinomial)
model . fit ( X , y ) # Entrainement
2023-06-20 12:07:47 +02:00
###############################################################################
# Phase d'inférence
###############################################################################
2023-06-22 03:14:37 +02:00
# Analyse 1D
y1_predict_1d = model_1d . predict ( x2_new ) # Prédiction
y1_proba_1d = model_1d . predict_proba ( x2_new ) # Probabilité
frontiere_decision_1d = x2_new [ y1_proba_1d [ : , 1 ] > = 0.5 ] [ 0 ] [ 0 ]
# Analyse 2D
y1_predict_2d = model_2d . predict ( X_new ) # Prédiction
y1_proba_2d = model_2d . predict_proba ( X_new ) # Probabilité
2023-06-24 09:13:47 +02:00
model_2d_a = - model_2d . coef_ [ 0 ] [ 0 ] / model_2d . coef_ [ 0 ] [ 1 ] # coef directeur de la frontière de décision
model_2d_b = - model_2d . intercept_ / model_2d . coef_ [ 0 ] [ 1 ] # ordonée à l'origine de la frontière de décision
frontiere_decision_2d = model_2d_a * x1_new + model_2d_b
2023-06-22 03:14:37 +02:00
y1_proba_2d_contour = y1_proba_2d [ : , 1 ] . reshape ( x1_new_mg . shape )
# Analyse multi-classes (Softmax)
y_predict = model . predict ( X_new ) # Prédiction
y_proba = model . predict_proba ( X_new ) # Probabilité
y_proba_contour0 = y_proba [ : , 0 ] . reshape ( x1_new_mg . shape )
y_proba_contour1 = y_proba [ : , 1 ] . reshape ( x1_new_mg . shape )
y_proba_contour2 = y_proba [ : , 2 ] . reshape ( x1_new_mg . shape )
y_predict_map = y_predict . reshape ( x1_new_mg . shape )
2023-06-20 12:07:47 +02:00
###############################################################################
# Résultats
###############################################################################
2023-06-22 03:14:37 +02:00
# Plot x1,y1 (largeur de pétale, probabilité d'être Iris virginica)
donnees1_ax . set_title ( " Binomiale - Frontière de décision à 1 entrée " )
donnees1_ax . plot ( x2_new , y1_proba_1d [ : , 1 ] , ' b: ' , label = " Probabilité " )
donnees1_ax . plot ( x2_new , y1_predict_1d , ' y- ' , label = " Prédictions " )
donnees1_ax . set_xlabel ( r ' $x_2$ ' + " - Largeur de pétale " )
donnees1_ax . set_ylabel ( r ' $y$ ' + " - Probabilité d ' être Iris virginica " )
donnees1_ax . legend ( loc = " center left " )
2023-06-24 09:13:47 +02:00
# Plot x1,x2 et y1 (longeur de pétale, largeur de pétale et probabilité d'être Iris virginica)
2023-06-22 03:14:37 +02:00
donnees2_ax . set_title ( " Binomiale - Frontière de décision à 2 entrées " )
donnees2_ax . set ( xlim = ( 0 , 7.5 ) , ylim = ( 0 , 3.5 ) )
2023-06-24 09:13:47 +02:00
donnees2_ax . plot ( x1_new , frontiere_decision_2d , " k-- " )
2023-06-22 03:14:37 +02:00
donnees2_ax . set_xlabel ( r ' $x_1$ ' + " - Longueur de pétale " )
donnees2_ax . set_ylabel ( r ' $x_2$ ' + " - Largeur de pétale " )
donnees2_ax . legend ( loc = " upper left " )
donnees2_contour = donnees2_ax . contour ( x1_new_mg , x2_new_mg , y1_proba_2d_contour , cmap = plt . cm . brg ) # Contour pour la classe Iris versicolor (type 1)
donnees2_ax . clabel ( donnees2_contour , inline = 1 , fontsize = 10 )
2023-06-24 09:13:47 +02:00
# Plot x1,x2 et y (longeur de pétale, largeur de pétale et type de Iris (format de la marque))
2023-06-22 03:14:37 +02:00
donnees3_ax . set_title ( " Multinomiale (régression Softmax) " )
donnees3_ax . set ( xlim = ( 0 , 7.5 ) , ylim = ( 0 , 3.5 ) )
donnees3_ax . set_xlabel ( r ' $x_1$ ' + " - Longueur de pétale " )
donnees3_ax . set_ylabel ( r ' $x_2$ ' + " - Largeur de pétale " )
donnees3_ax . legend ( loc = " upper right " )
custom_cmap = ListedColormap ( [ ' #fafab0 ' , ' #9898ff ' , ' #a0faa0 ' ] )
donnees3_ax . contourf ( x1_new_mg , x2_new_mg , y_predict_map , cmap = custom_cmap )
donnees3_contour = donnees3_ax . contour ( x1_new_mg , x2_new_mg , y_proba_contour1 , cmap = plt . cm . brg ) # Contour pour la classe Iris versicolor (type 1)
donnees3_ax . clabel ( donnees3_contour , inline = 1 , fontsize = 10 )
2023-06-20 12:07:47 +02:00
plt . show ( )
# Performances
2023-06-22 03:14:37 +02:00
print ( " Frontière de décision 1D sur la largeur de pétale : " + str ( round ( frontiere_decision_1d , 6 ) ) )
2023-06-20 12:07:47 +02:00
print ( " Temps : " + str ( time . time ( ) - t_debut ) )