← Retourner à la liste des articles
Image blog
Auteur

Par Maxime Jumelle

CTO & Co-Founder

Publié le 4 déc. 2020

Catégorie Machine Learning

Matplotlib et les fonctions à deux variables

Dans certaines situations, il est indispensable d'afficher sur un graphique l'évolution d'une quantité en fonction de deux variables : c'est le cas par exemple lorsque l'on souhaite savoir comment le prix d'un déménagement va évoluer selon la distance entre le départ et l'arrivé, ainsi que le volume nécessaire. On rencontre également ce genre de besoin pour afficher des températures en fonction de la localisation.

Il s'agit donc de tracer des graphiques à deux variables. Mais voilà, cela paraît compliqué avec matplotlib, qui est habituellement utilisé pour dessiner des courbes. Dans cet article, nous allons voir comment il est facile de dessiner des surfaces avec les mesh et les contour.

Fonctions à deux variables

Prenons le cas d'une fonction simple à deux variables, où la quantité Z est égale à une exponentielle multiplié par l'inverse du carré du produit de deux quantités. Pour cela, nous devons générer des points sur les deux axes x et y.

import numpy as np
import matplotlib.pyplot as plt

density = 100

x = np.linspace(-1, 1, num=density)
y = np.linspace(-1, 1, num=density)

À lire aussi : découvrez notre formation MLOps


Il y a deux éléments essentiels ici :

  • La fonction np.linspace va permettre de générer un nombre de valeurs entre deux bornes (ici, -1 et 1).
  • La variable density permet de spécifier le nombre de valeurs qui vont être générées.

L'avantage de la fonction np.linspace est que les points générés seront équidistants : l'écart sera identique entre deux valeurs successives, comme nous pouvons le vérifier ici.

np.diff(x)

Nous avons choisi une densité de 100 points entre -1 et 1, aussi bien pour x que pour y.

Avec la fonction np.meshgrid, nous allons construire une surface en générant un nombre de points par produit cartésien sur les deux axes spécifiés.

X, Y = np.meshgrid(x, y)

plt.figure(figsize=(13,11))
plt.scatter(X.flatten(), Y.flatten(), s=2)

Chaque point représente un élément de la grille. Il nous reste plus qu'à calculer Z en chacun des points pour ensuite utilise plt.pcolor pour dessiner par interpolation la fonction à deux variables.

Z = np.exp(-5 * (X * Y)**2)

plt.figure(figsize=(13,11))
plt.pcolor(X, Y, Z)

Avec la fonction plt.pcolor, chaque point est remplacé par un rectangle dont la couleur dépend de la valeur de Z. Sur cette palette de couleur, plus Z est élevée, plus la couleur est jaune.

Si l'on utilise encore la fonction plt.scatter, nous pouvons voir que le résultat est similaire, si ce n'est qu'à la place de petits rectangles, ce sont les points qui sont colorés différemment.

plt.figure(figsize=(13,11))
plt.scatter(X.flatten(), Y.flatten(), s=2, c=Z)

Comme tout graphique de matplotlib, il est possible de modifier la palette de couleur, ajouter une légende (ici une colorbar) ou modifier les axes.

plt.figure(figsize=(13,11))
plt.pcolor(X, Y, Z, cmap=plt.get_cmap("plasma"))
plt.colorbar()

Exemple : optimisation d'hyper-paramètres avec une grille aléatoire

Prenons un exemple concret où l'on souhaite optimiser les hyper-paramètres d'un modèle de Machine Learning avec une recherche par grille aléatoire.

n = 10000 # Taille de l'échantillon

np.random.seed(1)

X = np.random.randint(10, size=(n, 20))
y = np.mean(np.exp(-np.abs(X)**2), axis=1)

Nous venons de générer une base d'apprentissage. Nous allons essayer de modéliser y en fonction de X avec un arbre de régression, dont nous allons chercher à trouver le max_depth ainsi que le min_samples_split optimaux.

from sklearn.model_selection import RandomizedSearchCV
from sklearn.tree import DecisionTreeRegressor
from scipy.stats import binom, geom

# On spécifie les lois de probabilité pour chaque hyper-paramètre
grid_parameters = {
    'max_depth': binom(n=300, p=0.05),
    'min_samples_split': geom(loc=1, p=0.5)
}

grid_random_cv = RandomizedSearchCV(
    DecisionTreeRegressor(),
    grid_parameters,
    scoring="r2",
    cv=5,
    n_iter=20
)

# On lance la recherche aléatoire
grid_random_cv.fit(X, y)

À lire aussi : découvrez notre formation MLOps


Cette recherche par grille va générer 20 points selon les distributions aléatoires spécifiés, calibrer un arbre de régression avec les hyper-paramètres correspondant pour ensuite calculer le score R2.

from scipy.interpolate import interp2d

params_x = [d['max_depth'] for d in grid_random_cv.cv_results_['params']]
params_y = [d['min_samples_split'] for d in grid_random_cv.cv_results_['params']]
scores = grid_random_cv.cv_results_['mean_test_score']

Z_interp = interp2d(params_x, params_y, scores, kind="cubic")

density = 100
x = np.linspace(min(params_x) - 1, max(params_x) + 1, num=density)
y = np.linspace(min(params_y) - 1, max(params_y) + 1, num=density)
X, Y = np.meshgrid(x, y)
Z = Z_interp(x, y)

Avec la fonction interp2d, on effectue une interpolation, permettant de générer des observations entre les 20 points de la grille et l'espace utilisé.

fig = plt.figure(figsize=(14, 9))
plt.pcolor(X, Y, Z)
plt.colorbar()
plt.xlabel("max_depth")
plt.ylabel("min_samples_split")

La fonction contourf peut être plus intéressante dans ce contexte, puisqu'elle va calculer des isolignes (lignes de l'espace où Z est constant) et dessiner des niveaux différents.

fig = plt.figure(figsize=(14, 9))
# On ne dessine que 10 isolignes
plt.contourf(X, Y, Z, 10, cmap=plt.get_cmap("plasma"))
plt.colorbar()
plt.xlabel("max_depth")
plt.ylabel("min_samples_split")

Dans certains cas, il est même préférable d'afficher également sur le graphique les isolignes.

fig = plt.figure(figsize=(14, 9))

class fmt(float):
    def __repr__(self):
        return f'{self:.0f}'

contour = plt.contourf(X, Y, Z, 10, cmap=plt.get_cmap("plasma"))
plt.colorbar()
ax = plt.gca()
contour.levels = [fmt(val * 100) for val in contour.levels[:-1]]
ax.clabel(contour, contour.levels, inline=True, fmt=r'%r %%', fontsize=12, colors="k")


plt.xlabel("max_depth")
plt.ylabel("min_samples_split")

Vous souhaitez vous former au MLOps ?

Articles similaires

Blog

20 sept. 2022

Machine Learning

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.

Nada Belaidi

Équipe Blent

Data Scientist

Lire l'article

Blog

12 juil. 2022

Machine Learning

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.

Nada Belaidi

Équipe Blent

Data Scientist

Lire l'article

Blog

4 juil. 2022

Machine Learning

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.

Nada Belaidi

Équipe Blent

Data Scientist

Lire l'article