{
"cells": [
{
"cell_type": "markdown",
"id": "2dc386c4",
"metadata": {},
"source": [
"\n",
""
]
},
{
"cell_type": "markdown",
"id": "1a40817d",
"metadata": {},
"source": [
"# Travaux pratiques - Evaluation et sélection de modèles décisionnels\n",
"\n",
"**L’objectif** de cette séance de travaux pratiques est de montrer l’utilisation des techniques de validation croisée pour l’évaluation et la comparaison de modèles décisionnels, ainsi que des méthodes de recherche de valeurs pour les hyper-paramètres (comme le coefficient de régularisation).\n",
"\n",
"Références externes utiles :\n",
"\n",
"> - [Documentation NumPy](https://docs.scipy.org/doc/numpy/user/index.html) \n",
"- [Documentation SciPy](https://docs.scipy.org/doc/scipy/reference/) \n",
"- [Documentation MatPlotLib](http://matplotlib.org/) \n",
"- [Site scikit-learn](http://scikit-learn.org/stable/index.html) \n",
"- [Site langage python](https://www.python.org) "
]
},
{
"cell_type": "markdown",
"id": "59c5d634",
"metadata": {},
"source": [
"## Estimation des performances par validation croisée\n",
"\n",
"Afin d’illustrer l’utilisation de la validation croisée, nous considérons un problème de classement similaire à celui examiné lors de la précédente séance. Nous considérons un jeu de données pour lequel nous disposons de l’information de supervision (les étiquettes des classes) et nous le partitionnons en un ensemble d’apprentissage et un ensemble de test. Nous utiliserons les [Iris de Fisher](https://fr.wikipedia.org/wiki/Iris_de_Fisher) comme jeu de données. Pour rappel, celui-ci consiste à identifier à quelle espèce appartient une plante parmi trois possibilités (*Iris Setosa*, *Iris Virginica* et *Iris Versicolor*) à partir de la longueur et la largeur des sépales et des pétales.\n",
"\n",
"Nous employons des perceptrons multi-couches (PMC) avec une seule couche cachée de 100 neurones et une valeur $ \\alpha = 1 $ pour la constante de régularisation (pondération du terme d’oubli ou *weight decay*). Il n’est pas indispensable pour cette séance de savoir en détails comment fonctionne ces réseaux de neurones, ces modèles décisionnels seront revus plus tard dans le cours.\n",
"\n",
"La validation croisée sera utilisée pour estimer les performances de généralisation *à partir de l’ensemble d’apprentissage*. Ensuite, cette estimation sera comparée à l’estimation obtenue sur l’ensemble de test que nous avions mis de côté au départ. Les explications sur la validation croisée et sa mise en œuvre dans Scikit-learn se trouvent [dans la documentation](http://scikit-learn.org/stable/modules/cross_validation.html)."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e025060f",
"metadata": {
"hide-output": false
},
"outputs": [],
"source": [
"# importations\n",
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"import sklearn\n",
"\n",
"# chargement du jeu de données Iris\n",
"from sklearn import datasets\n",
"iris = datasets.load_iris()\n",
"data, labels = iris.data, iris.target\n",
"\n",
"# découpage initial en données d'apprentissage et données de test\n",
"from sklearn.model_selection import train_test_split\n",
"X_train, X_test, y_train, y_test = train_test_split(data, labels, test_size=0.5)"
]
},
{
"cell_type": "markdown",
"id": "91022849",
"metadata": {},
"source": [
"La fonction train_test_split de scikit-learn nous permet de diviser aléatoirement le jeu de données en deux partitions train (apprentissage) et test (évaluation) selon des proportions arbitraires.\n",
"\n",
"Comme d’habitude, il est intéressant de visualiser les données à notre disposition. Nous pouvons construire les nuages de points en deux dimensions à l’aide de Matplotlib :"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "c2603a47",
"metadata": {
"hide-output": false
},
"outputs": [],
"source": [
"fig = plt.figure(figsize=(16, 12))\n",
"n_features = data.shape[-1]\n",
"n_plots = 6\n",
"idx = 1\n",
"cmp = np.array(['r', 'g', 'b'])\n",
"for dim1 in range(0, n_features):\n",
" for dim2 in range(dim1+1, n_features):\n",
" fig.add_subplot(2, n_plots // 2, idx)\n",
" plt.scatter(X_train[:, dim1], X_train[:, dim2],c=cmp[y_train], s=50, edgecolors='none')\n",
" plt.scatter(X_test[:, dim1], X_test[:, dim2], c='none', s=50, edgecolors=cmp[y_test])\n",
" plt.xlabel(iris.feature_names[dim1])\n",
" plt.ylabel(iris.feature_names[dim2])\n",
" idx += 1\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"id": "6c8a8508",
"metadata": {},
"source": [
"## Question\n",
"\n",
"Pourquoi a-t-on six nuages de points différents ? Que représente chaque figure ?\n",
"\n",
"Pour ce problème de classement, nous allons utiliser un PMC avec les valeurs par défaut proposés par scikit-learn pour le nombre de couches (1) et de neurones (100)."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "0472cf7e",
"metadata": {
"hide-output": false
},
"outputs": [],
"source": [
"# emploi de PMC\n",
"from sklearn.neural_network import MLPClassifier\n",
"clf = MLPClassifier(solver='lbfgs', alpha=1, tol=5e-3)"
]
},
{
"cell_type": "markdown",
"id": "0ebd20ca",
"metadata": {},
"source": [
"Pour estimer l’erreur de généralisation, nous allons utiliser la validation croisée *K-fold*. Cela va nous permettre d’ajuster, si besoin, les hyperparamètres du modèle décisionnel. scikit-learn implémente diverses stratégies de validation croisée dans le module sklearn.model_selection. Commençons par expérimenter avec l’approche *K-fold*. L’objet KFold dispose d’une méthode .split() qui permet de générer les listes des indices des observations à utiliser pour le sous-jeu d’apprentissage et pour le sous-jeu de *validation*. Plus de détails sur cet objet se trouvent dans la [documentation de K-Fold](https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.KFold.html)."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "4175d2e5",
"metadata": {
"hide-output": false
},
"outputs": [],
"source": [
"# KFold pour différentes valeurs de k\n",
"from sklearn.model_selection import KFold\n",
"\n",
"# valeurs de k\n",
"n_folds = np.array([2, 3, 5, 7, 10, 13, 16, 20])\n",
"\n",
"# préparation des listes pour stocker les résultats\n",
"cv_scores = []\n",
"cv_scores_std = []\n",
"\n",
"for k in n_folds: # pour chaque valeur de k\n",
" kf = KFold(n_splits=k)\n",
" scores = []\n",
" # apprentissage puis évaluation d'un modèle sur chaque split\n",
" for train_idx, val_idx in kf.split(X_train):\n",
" # apprentissage avec .fit()\n",
" clf.fit(X_train[train_idx], y_train[train_idx])\n",
" scores.append(clf.score(X_train[val_idx], y_train[val_idx]))\n",
" # calcul de la moyenne et de l'écart-type des performances obtenues\n",
" cv_scores.append(np.mean(scores))\n",
" cv_scores_std.append(np.std(scores))\n",
"\n",
"cv_scores, cv_scores_std = np.array(cv_scores), np.array(cv_scores_std)\n",
"\n",
"# affichage performance moyenne +- 1 écart-type pour chaque k\n",
"plt.figure(figsize=(8, 6))\n",
"plt.plot(n_folds, cv_scores, 'b')\n",
"plt.fill_between(n_folds, cv_scores + cv_scores_std, cv_scores - cv_scores_std, alpha=0.5)\n",
"plt.xlabel(\"Valeur de $k$ du K-Fold\")\n",
"plt.ylabel(\"Score moyen\")\n",
"plt.xlim(2, max(n_folds))\n",
"plt.xticks(n_folds)\n",
"plt.title(\"Erreur de généralisation estimée en fonction de $k$\")\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"id": "bb5b8412",
"metadata": {},
"source": [
"## Question :\n",
"\n",
"Que constatez-vous en examinant ce graphique ? Ajoutez des valeurs pour *k* (par ex. 40, 100, attention ce sera plus long…) et examinez de nouveau le graphique."
]
},
{
"cell_type": "markdown",
"id": "734a9600",
"metadata": {},
"source": [
"## Question :\n",
"\n",
"Pour chaque modèle appris par validation croisée *k-fold*, ajoutez son évaluation sur les données de test mises de côté au départ `X_test, y_test`. Affichez les courbes sur le même graphique. Que constatez-vous ?"
]
},
{
"cell_type": "markdown",
"id": "b8ae446e",
"metadata": {},
"source": [
"## Question :\n",
"\n",
"Réalisez l’estimation des performances en utilisant la [validation croisée leave one out (LOO)](http://scikit-learn.org/stable/modules/generated/sklearn.model_selection.LeaveOneOut.html#sklearn.model_selection.LeaveOneOut). Que constatez-vous en comparant les résultats de *k-fold* et de *leave one out* ?"
]
},
{
"cell_type": "markdown",
"id": "6be9a57d",
"metadata": {},
"source": [
"## Note\n",
"\n",
"Pour l’illustration, nous avons itéré ici manuellement à l’aide des itérateurs KFold et LeaveOneOut. Toutefois il est possible d’automatiser ce procédé dans le cas du *KFold* à l’aide de la fonction cross_val_score:\n",
"\n",
"> > "
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "8f38788e",
"metadata": {
"hide-output": false
},
"outputs": [],
"source": [
"from sklearn.model_selection import cross_val_score\n",
"clf = MLPClassifier(solver='lbfgs', alpha=1, tol=5e-3)\n",
"\n",
"# Cross-validation KFold avec k=5\n",
"scores = cross_val_score(clf, X_train, y_train, cv=5)"
]
},
{
"cell_type": "markdown",
"id": "1fcfa967",
"metadata": {},
"source": [
"\n",
"Cette fonction prend des paramètres supplémentaires (métriques, parallélisation, etc.) qui sont décrites dans [sa documentation](https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.cross_val_score.html#sklearn.model_selection.cross_val_score)."
]
},
{
"cell_type": "markdown",
"id": "5a31518f",
"metadata": {},
"source": [
"## Évaluation d’un classifieur binaire\n",
"\n",
"Précédemment, nous avons évalué le modèle en calculant le taux de bonnes prédictions (*accuracy*). Néanmoins, cette métrique est biaisée en faveur des classes les plus représentées lorsque le jeu de données est déséquilibré. Une alternative courante, notamment dans le cas de la classification binaire, est de s’intéresser au taux de faux positifs et au taux de faux négatifs.\n",
"\n",
"Pour illustrer ces concepts, considérons le jeu de données *Breast Cancer Wisconsin*. Ce jeu de données comporte 569 observations pour 30 variables médicales obtenues par biopsie. Les observations sont réparties dans deux classes: tumeur maligne (0) ou tumeur bénigne (1)."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "7a7d87d5",
"metadata": {
"hide-output": false
},
"outputs": [],
"source": [
"from sklearn.datasets import load_breast_cancer\n",
"# Chargement des données *Breast Cancer Wisconsin*\n",
"X, y = load_breast_cancer(return_X_y=True)"
]
},
{
"cell_type": "markdown",
"id": "1dd962fe",
"metadata": {},
"source": [
"## Question\n",
"\n",
"Combien y a-t-il de tumeurs bénignes dans ce jeu de données? De tumeurs malignes?\n",
"\n",
"Dans un premier temps, nous allons diviser le jeu de données en deux : un jeu d’apprentissage et un jeu de validation. Comme il s’agit d’un problème de classification binaire, nous allons tracer la courbe ROC (*Receiver Operating Characteristic*), qui correspond au taux de vrais positifs en fonction du taux de faux positifs."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "9eb88f3c",
"metadata": {
"hide-output": false
},
"outputs": [],
"source": [
"# Division du jeu de données (50%/50%)\n",
"from sklearn.model_selection import train_test_split\n",
"X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.5, random_state=0)"
]
},
{
"cell_type": "markdown",
"id": "e8a139bd",
"metadata": {},
"source": [
"Entraînons deux modèles sur ce jeu de données : un percepton multi-couches (MLPClassifier) et une analyse factorielle discriminante (LinearDiscriminantAnalysis)."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "25b0b75f",
"metadata": {
"hide-output": false
},
"outputs": [],
"source": [
"from sklearn.neural_network import MLPClassifier\n",
"\n",
"mlp = MLPClassifier(hidden_layer_sizes=50, alpha=1e-5, max_iter=1000, solver='adam', random_state=0)\n",
"mlp.fit(X_train, y_train)\n",
"print(f\"Accuracy du MLP: {mlp.score(X_test, y_test)*100:.1f}%\")\n",
"\n",
"\n",
"from sklearn.discriminant_analysis import LinearDiscriminantAnalysis\n",
"\n",
"lda = LinearDiscriminantAnalysis()\n",
"lda.fit(X_train, y_train)\n",
"print(f\"Accuracy de la LDA: {lda.score(X_test, y_test)*100:.1f}%\")"
]
},
{
"cell_type": "markdown",
"id": "71c1816e",
"metadata": {},
"source": [
"Comme nous l’avons vu, l”*accuracy* est une métrique biaisée en faveur de la classe la plus représentée. À la place, nous pouvons calculer la précision et le rappel pour chaque classe. Dans notre cas, c’est notamment la précision et le rappel sur la classe 0 (tumeur maligne) qui nous intéresse : cela nous permettra d’évaluer combien de fausses alarmes ont été produites et combien de tumeur malignes ont été « ratées ».\n",
"\n",
"scikit-learn propose une [fonction bien utile](https://scikit-learn.org/stable/modules/generated/sklearn.metrics.classification_report.html) permettant de résumer ces métriques de classification :"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "dde16dd0",
"metadata": {
"hide-output": false
},
"outputs": [],
"source": [
"from sklearn.metrics import classification_report\n",
"\n",
"print(\"\\t========= Métriques pour le MLP ============\")\n",
"print(classification_report(y_test, mlp.predict(X_test)))"
]
},
{
"cell_type": "markdown",
"id": "2d588e03",
"metadata": {},
"source": [
"## Question\n",
"\n",
"Calculer ces mêmes métriques pour l’analyse factorielle discriminante (*LDA*).\n",
"\n",
"Pour tracer la courbe ROC, nous devons maintenant calculer les taux de vrais positifs et de faux positifs pour différentes valeurs du seuil de classification. La plupart des classifieurs produisent en sortie une probabilité d’appartenance à chaque classe, entre 0 et 1. Si l’on ne spécifie rien, la règle consiste la plupart du temps à assigner une observation $ x $ à la classe $ k $ si la probabilité assignée par le modèle pour $ x $ à la $ k $ est supérieure à 0,5. Toutefois, nous pouvons faire varier ce seuil. Si on diminue le seuil, alors de plus en plus d’observations sont assignées à la classe $ k $: le taux de vrais positifs augmente mais le taux de faux positifs aussi. Et inversement si l’on diminue ce seuil.\n",
"\n",
"La courbe ROC correspondent à l’ensemble des points (taux de faux positifs, taux de vrais positifs) obtenus en faisant varier le seuil de décision entre 0 et 1.\n",
"\n",
"scikit-learn permet de calculer automatiquement les taux de vrais positifs et faux positifs pour différents points de fonctionnement à l’aide de la méthode `metrics.roc_curve` (cf. [documentation](https://scikit-learn.org/stable/modules/generated/sklearn.metrics.roc_curve.html)):"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "9ded15b6",
"metadata": {
"hide-output": false
},
"outputs": [],
"source": [
"from sklearn.metrics import roc_curve\n",
"\n",
"# Calcul de la courbe ROC\n",
"# `pos_label` permet d'indiquer que l'étiquette \"positive\" (tumeur maligne\")\n",
"# correspond à la valeur 0\n",
"fpr, tpr, thresholds = roc_curve(y_test, mlp.predict_proba(X_test)[:,0], pos_label=0)\n",
"\n",
"plt.plot(fpr, tpr, label=\"MLP\")\n",
"plt.xlim(-0.05, 1)\n",
"plt.ylim(0, 1.05)\n",
"plt.title(\"Courbes ROC\")\n",
"plt.xlabel(\"Taux de faux positifs\")\n",
"plt.ylabel(\"Taux de vrais positifs\")\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"id": "fbf556a5",
"metadata": {},
"source": [
"## Question\n",
"\n",
"Calculer et tracer en superposition la courbe ROC pour la *LDA*. Quel modèle vous semble le plus approprié pour ce jeu de données ? Quelle métrique pourrait-on calculer pour confirmer cette hypothèse ?"
]
},
{
"cell_type": "markdown",
"id": "a48232f0",
"metadata": {},
"source": [
"## Question\n",
"\n",
"On souhaite un taux de faux positifs inférieur à 10% (c’est-à-dire que moins d’une tumeur prédite comme « maligne » sur 10 soit en réalité bénigne). Déterminer pour le modèle de votre choix la valeur du seuil pour la classe 0 (tumeur maligne) permettant d’atteindre cet objectif. À quel taux de vrais positifs cela correspond-t-il ?"
]
},
{
"cell_type": "markdown",
"id": "807b53e0",
"metadata": {},
"source": [
"### Pour aller plus loin\n",
"\n",
"Pour simplifier, nous avons ici considéré une division *train/test* en deux parties. Toutefois, comme nous l’avons vu précédemment, il serait plus rigoureux de réaliser une validation croisée, par exemple *K-Fold*. scikit-learn permet de réaliser une validation croisée en spécifiant la métrique à conserver."
]
},
{
"cell_type": "markdown",
"id": "7ea6d016",
"metadata": {},
"source": [
"### Question\n",
"\n",
"(*À terminer chez vous*) Réaliser une validation croisée *KFold* sur le modèle de votre choix en utilisant l’aire sous la courbe ROC (`metrics.roc_auc_score`) comme métrique de référence. La [ "
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "da9f3aa1",
"metadata": {
"hide-output": false
},
"outputs": [],
"source": [
"from sklearn.model_selection import GridSearchCV"
]
},
{
"cell_type": "markdown",
"id": "0bd08e40",
"metadata": {},
"source": [
"\n",
"Il est nécessaire d’indiquer dans un « dictionnaire » quels sont les hyperparamètres dont on souhaite explorer les valeurs et quelles sont les différentes valeurs à évaluer. Chaque entrée du dictionnaire consiste en une chaîne de caractères qui contient le nom de l’hyperparamètre tel qu’il est défini dans l’estimateur employé. Nous nous servirons ici de `MLPClassifier`, les noms des paramètres peuvent donc être trouvés dans [la présentation de cette classe](http://scikit-learn.org/stable/modules/generated/sklearn.neural_network.MLPClassifier.html#sklearn.neural_network.MLPClassifier). Nous considérons ici seulement deux paramètres, `hidden_layer_sizes` (nombre de neurones dans l’unique couche cachée) et `alpha` (la constante $ \\alpha $ de régularisation par *weight decay*)."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ad6414c9",
"metadata": {
"hide-output": false
},
"outputs": [],
"source": [
"tuned_parameters = {'hidden_layer_sizes':[(5,), (20,), (50,), (100,), (150,), (200,)],\n",
" 'alpha': [0.001, 0.01, 1, 2]}"
]
},
{
"cell_type": "markdown",
"id": "6fb34fcb",
"metadata": {},
"source": [
"Dans l’appel de `GridSearchCV` nous indiquons ensuite pour `MLPClassifier` le solveur à utiliser systématiquement (qui n’est pas celui par défaut), ensuite le dictionnaire avec les valeurs des (hyper)paramètres à explorer et enfin le fait que c’est la validation croisée *k-fold* avec $ k=5 $ qui est employée pour comparer les différents modèles."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "4db3859d",
"metadata": {
"hide-output": false
},
"outputs": [],
"source": [
"clf = GridSearchCV(MLPClassifier(solver='lbfgs', tol=5e-3), tuned_parameters, cv=5)\n",
"\n",
"# exécution de grid search\n",
"clf.fit(X_train, y_train)"
]
},
{
"cell_type": "markdown",
"id": "1f359177",
"metadata": {},
"source": [
"Scikit-learn exécute alors le programme suivant :\n",
"\n",
"- à partir des listes de valeurs pour les différents (hyper)paramètres sont générées toutes les combinaisons de valeurs, \n",
"- pour chaque combinaison, les performances des modèles correspondants sont évaluées par validation croisée *5-fold* (appliquée uniquement sur les **données d’apprentissage** `X_train, y_train`), \n",
"- sont sélectionnées les valeurs des (hyper)paramètres correspondant aux meilleures performances de validation croisée, \n",
"- avec ces valeurs pour les (hyper)paramètres un nouvel apprentissage est réalisé avec la totalité des données de `X_train, y_train` (et non seulement $ \\frac{k-1}{k} $ *folds*). \n",
"\n",
"\n",
"Les lignes suivantes permettent d’afficher les résultats : les paramètres du meilleur modèle avec `clf.best_params_`, ainsi que les résultats de validation croisée obtenus pour toutes les combinaisons de valeurs pour les (hyper)paramètres (`clf.cv_results_` donne accès à ces informations et à bien d’autres)."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b611e209",
"metadata": {
"hide-output": false
},
"outputs": [],
"source": [
"print(clf.best_params_)"
]
},
{
"cell_type": "markdown",
"id": "bead8e12",
"metadata": {},
"source": [
"Nous pouvons également faire un affichage plus complet, traçant la surface du score moyen des différentes modèles en fonction de la combinaison des deux hyperparamètres :"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "97dbf09a",
"metadata": {
"hide-output": false
},
"outputs": [],
"source": [
"n_hidden = np.array([s[0] for s in tuned_parameters['hidden_layer_sizes']])\n",
"alphas = np.array(tuned_parameters['alpha'])\n",
"\n",
"# création de la grille des hyperparamètres\n",
"xx, yy = np.meshgrid(n_hidden, alphas)\n",
"scores = clf.cv_results_['mean_test_score'].reshape(xx.shape)\n",
"\n",
"# affichage sous forme de fil de fer de la surface des résultats des modèles évalués\n",
"from mpl_toolkits.mplot3d import Axes3D\n",
"fig = plt.figure(figsize=(8, 6))\n",
"ax = plt.axes(projection='3d')\n",
"ax.set_xlabel(\"Neurones cachés\")\n",
"ax.set_ylabel(\"Régularisation $\\\\alpha$\")\n",
"ax.set_zlabel(\"Taux de bon classement\")\n",
"ax.plot_wireframe(xx, yy, scores)\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"id": "27b79d89",
"metadata": {},
"source": [
"Nous avons employé ici `plot_wireframe` car la lisibilité est meilleure qu’avec `plot_surface`."
]
},
{
"cell_type": "markdown",
"id": "c826ab15",
"metadata": {},
"source": [
"## Question :\n",
"\n",
"Combien de PMC au total sont appris pendant la validation croisée dans cet exemple ?"
]
},
{
"cell_type": "markdown",
"id": "5c7b653b",
"metadata": {},
"source": [
"## Question :\n",
"\n",
"Quelle est la signification du paramètre `refit` de `GridSearchCV` ?"
]
},
{
"cell_type": "markdown",
"id": "7059140d",
"metadata": {},
"source": [
"## Question :\n",
"\n",
"Examinez de façon plus complète le contenu de `clf.cv_results_`."
]
},
{
"cell_type": "markdown",
"id": "4a3051d9",
"metadata": {},
"source": [
"## Question :\n",
"\n",
"Evaluez le modèle sélectionné sur les données de test (`X_test, y_test`)."
]
},
{
"cell_type": "markdown",
"id": "694cd132",
"metadata": {},
"source": [
"## Question :\n",
"\n",
"L’aspect des résultats vous incite à affiner la grille ? Modifiez la grille et examinez les nouveaux résultats."
]
},
{
"cell_type": "markdown",
"id": "17161ddb",
"metadata": {},
"source": [
"## Question :\n",
"\n",
"Utilisez la recherche aléatoire avec [RandomizedSearchCV](http://scikit-learn.org/stable/modules/generated/sklearn.model_selection.RandomizedSearchCV.html#sklearn.model_selection.RandomizedSearchCV). Le « budget » (nombre total de combinaisons évaluées) peut être fixé avec `n_iter`. Motivez le choix des lois employées pour le tirage des valeurs des deux (hyper)paramètres `hidden_layer_sizes` et `alpha`."
]
},
{
"cell_type": "markdown",
"id": "695b61e2",
"metadata": {},
"source": [
"### Pour aller plus loin\n",
"\n",
"D’autres stratégies plus avancées de sélection d’hyperparamètres sont envisageables. En effet, la recherche par grille, comme la recherche aléatoire, sont des méthodes relativement rudimentaires et plutôt coûteuses en ressources. Cela peut notamment poser problème lorsque les modèles décisionnels que l’on considère appartiennent à une famille paramétrique coûteuse en calculs, comme les réseaux de neurones profonds.\n",
"\n",
"scikit-learn propose ainsi une implémentation expérimentale d’une recherche par dichotomie, permettant de concentrer les ressources sur les combinaisons d’hyperparamètres les plus prometteuses."
]
},
{
"cell_type": "markdown",
"id": "192f3fe5",
"metadata": {},
"source": [
"### Question\n",
"\n",
"(*À terminer chez vous*) Expérimenter avec HalvingGridSearchCV (cf. [la documentation](https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.HalvingGridSearchCV.html#sklearn.model_selection.HalvingGridSearchCV)). Comparer notamment le score final et le temps de calcul à celui obtenu avec GridSearchCV."
]
},
{
"cell_type": "markdown",
"id": "a6e35b4e",
"metadata": {},
"source": [
"### Note\n",
"\n",
"Hors de scikit-learn, il existe également d’autres bibliothèques implémentant des stratégies avancées de sélection utilisant diverses heuristiques pour choisir les combinaisons d’hyperparamètres à explorer. Certaines de ces bibliothèques sont compatibles avec l’interface de scikit-learn, par exemple [tune-sklearn](https://github.com/ray-project/tune-sklearn) ou encore [sklearn-genetic-opt](https://github.com/rodrigo-arenas/Sklearn-genetic-opt)."
]
}
],
"metadata": {
"date": 1708014947.2670445,
"filename": "tpEvaluationSelectionModeles.rst",
"kernelspec": {
"display_name": "Python",
"language": "python",
"name": "python"
},
"title": "Travaux pratiques - Evaluation et sélection de modèles décisionnels"
},
"nbformat": 4,
"nbformat_minor": 5
}