mirror of
https://forge.apps.education.fr/phroy/mes-scripts-de-ml.git
synced 2024-01-27 11:30:36 +01:00
158 lines
7.4 KiB
Python
158 lines
7.4 KiB
Python
import time
|
|
import numpy as np
|
|
import sklearn
|
|
from sklearn.linear_model import LogisticRegression
|
|
from sklearn import datasets
|
|
import matplotlib.pyplot as plt
|
|
from matplotlib.colors import ListedColormap
|
|
|
|
###############################################################################
|
|
# 06-regression_logistique.py
|
|
# @title: Fondamentaux - Apprentissage par régression logistique
|
|
# @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
|
|
# - np.c_ : concatène les colonnes des tableaux
|
|
# - np.linspace : créer un tableau 1D de la valeur de début à la valeur de fin avec n valeurs
|
|
# - np.meshgrid : créer un tableau 2D avec l'ensemble des combinaisons allant des deux valeurs de début aux deux valeurs de fin
|
|
# - .reshape : reformater la tableau avec le nombre de lignes et le nombre de colonnes
|
|
###
|
|
|
|
###
|
|
# Commandes Scikit-Learn :
|
|
# - sklearn.linear_model.LogisticRegression : créer un modèle de régression logistique
|
|
# - 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
|
|
# - .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))
|
|
fig.suptitle("Classificateur par régression logistique")
|
|
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)
|
|
|
|
###############################################################################
|
|
# Observations
|
|
###############################################################################
|
|
|
|
# Observations d'apprentisage
|
|
iris = sklearn.datasets.load_iris() # Jeu de données Iris
|
|
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)")
|
|
|
|
# Nouvelles observations
|
|
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()]
|
|
|
|
###############################################################################
|
|
# Phase d'apprentissage
|
|
###############################################################################
|
|
|
|
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
|
|
|
|
###############################################################################
|
|
# Phase d'inférence
|
|
###############################################################################
|
|
|
|
# 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é
|
|
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
|
|
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)
|
|
|
|
###############################################################################
|
|
# Résultats
|
|
###############################################################################
|
|
|
|
# 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")
|
|
|
|
# Plot x1,x2 et y1 (longeur de pétale, largeur de pétale et probabilité d'être Iris virginica)
|
|
donnees2_ax.set_title("Binomiale - Frontière de décision à 2 entrées")
|
|
donnees2_ax.set(xlim=(0, 7.5), ylim=(0, 3.5))
|
|
donnees2_ax.plot(x1_new, frontiere_decision_2d, "k--")
|
|
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)
|
|
|
|
# Plot x1,x2 et y (longeur de pétale, largeur de pétale et type de Iris (format de la marque))
|
|
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)
|
|
plt.show()
|
|
|
|
# Performances
|
|
print ("Frontière de décision 1D sur la largeur de pétale : "+str(round(frontiere_decision_1d, 6)))
|
|
print ("Temps : "+str(time.time()-t_debut))
|