From 6a894ddbfcdaba8a0aeccebe0c1f87a75de89236 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20MARQUET?= <72651575+BreizhHardware@users.noreply.github.com> Date: Mon, 29 Sep 2025 15:19:43 +0200 Subject: [PATCH] Obisidian vault auto-backup: 29-09-2025 15:19:43 on . 1 files edited --- ISEN/IA/CIPA4/TP/TP2/tp2_IA.ipynb | 196 +++++++++++++++++++++++++++++- 1 file changed, 195 insertions(+), 1 deletion(-) diff --git a/ISEN/IA/CIPA4/TP/TP2/tp2_IA.ipynb b/ISEN/IA/CIPA4/TP/TP2/tp2_IA.ipynb index 2d8d60d..73d4406 100644 --- a/ISEN/IA/CIPA4/TP/TP2/tp2_IA.ipynb +++ b/ISEN/IA/CIPA4/TP/TP2/tp2_IA.ipynb @@ -1583,9 +1583,203 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 53, "id": "b4a6c352", "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "=== Calcul des métriques de performance avec sklearn.metrics ===\n", + "\n", + "Précision (Precision): 0.6687\n", + "Rappel (Recall): 0.8441\n", + "Score F1: 0.7462\n", + "\n", + "=== Interprétation des résultats ===\n", + "\n", + "1. PRÉCISION = 0.6687 (66.87%)\n", + " • Sur toutes les images que le modèle a classées comme '5',\n", + " 66.87% sont réellement des '5'\n", + " • 33.13% sont des faux positifs (erreurs)\n", + "\n", + "2. RAPPEL = 0.8441 (84.41%)\n", + " • Sur toutes les vraies images de '5' dans la base,\n", + " le modèle en a détecté 84.41%\n", + " • Il a manqué 15.59% des vrais '5' (faux négatifs)\n", + "\n", + "3. SCORE F1 = 0.7462 (74.62%)\n", + " • Moyenne harmonique entre précision et rappel\n", + " • Mesure équilibrée des performances globales\n", + "\n", + "=== Analyse comparative ===\n", + "✓ Rappel > Précision : Le modèle est plutôt libéral\n", + " → Il détecte bien les '5' mais fait quelques erreurs en trop\n", + "\n", + "✅ CONCLUSION: Performances BONNES (F1 ≥ 60%)\n" + ] + } + ], + "source": [ + "from sklearn.metrics import precision_score, recall_score, f1_score\n", + "\n", + "print(\"=== Calcul des métriques de performance avec sklearn.metrics ===\\n\")\n", + "\n", + "# Calculer la précision\n", + "precision = precision_score(y_train_5, y_train_pred)\n", + "print(f\"Précision (Precision): {precision:.4f}\")\n", + "\n", + "# Calculer le rappel\n", + "recall = recall_score(y_train_5, y_train_pred)\n", + "print(f\"Rappel (Recall): {recall:.4f}\")\n", + "\n", + "# Calculer le score F1\n", + "f1 = f1_score(y_train_5, y_train_pred)\n", + "print(f\"Score F1: {f1:.4f}\")\n", + "\n", + "print(f\"\\n=== Interprétation des résultats ===\")\n", + "\n", + "print(f\"\\n1. PRÉCISION = {precision:.4f} ({precision*100:.2f}%)\")\n", + "print(f\" • Sur toutes les images que le modèle a classées comme '5',\")\n", + "print(f\" {precision*100:.2f}% sont réellement des '5'\")\n", + "print(f\" • {(1-precision)*100:.2f}% sont des faux positifs (erreurs)\")\n", + "\n", + "print(f\"\\n2. RAPPEL = {recall:.4f} ({recall*100:.2f}%)\")\n", + "print(f\" • Sur toutes les vraies images de '5' dans la base,\")\n", + "print(f\" le modèle en a détecté {recall*100:.2f}%\")\n", + "print(f\" • Il a manqué {(1-recall)*100:.2f}% des vrais '5' (faux négatifs)\")\n", + "\n", + "print(f\"\\n3. SCORE F1 = {f1:.4f} ({f1*100:.2f}%)\")\n", + "print(f\" • Moyenne harmonique entre précision et rappel\")\n", + "print(f\" • Mesure équilibrée des performances globales\")\n", + "\n", + "print(f\"\\n=== Analyse comparative ===\")\n", + "if precision > recall:\n", + " print(f\"✓ Précision > Rappel : Le modèle est plutôt conservateur\")\n", + " print(f\" → Il évite les faux positifs mais manque quelques vrais '5'\")\n", + "elif recall > precision:\n", + " print(f\"✓ Rappel > Précision : Le modèle est plutôt libéral\")\n", + " print(f\" → Il détecte bien les '5' mais fait quelques erreurs en trop\")\n", + "else:\n", + " print(f\"✓ Précision ≈ Rappel : Modèle équilibré\")\n", + "\n", + "# Évaluation globale\n", + "if f1 >= 0.8:\n", + " print(f\"\\n🎯 CONCLUSION: Performances EXCELLENTES (F1 ≥ 80%)\")\n", + "elif f1 >= 0.6:\n", + " print(f\"\\n✅ CONCLUSION: Performances BONNES (F1 ≥ 60%)\")\n", + "elif f1 >= 0.4:\n", + " print(f\"\\n⚠️ CONCLUSION: Performances MOYENNES (F1 ≥ 40%)\")\n", + "else:\n", + " print(f\"\\n❌ CONCLUSION: Performances FAIBLES (F1 < 40%)\")" + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "id": "1ad09da3", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "=== Calcul des scores de décision avec cross_val_predict ===\n", + "\n", + "Type des scores: \n", + "Forme des scores: (60000,)\n", + "Type des éléments: \n", + "\n", + "Premiers 20 scores: [ 2233.76472412 -16999.83146625 -29880.24945215 -16853.32804962\n", + " -18123.62732289 -16786.05163476 -14344.66419922 -19160.60912277\n", + " -6866.69750684 -13676.7779591 -17430.53807378 764.86406397\n", + " -32548.13164662 -17809.33743497 -5282.69063153 -17399.14087231\n", + " -24825.67568325 -17165.2237745 -4832.03170209 -23564.24796162]\n", + "Derniers 20 scores: [ -2239.56847032 -12125.14890084 -6850.7198163 -20119.91822338\n", + " -11602.78108538 -24718.65480959 -4477.63088789 -7211.15680865\n", + " -6894.02349027 -6421.21472386 -9677.81738926 -10311.26010833\n", + " -3368.75566452 5493.88995718 -3859.07168195 -11446.19872796\n", + " -10968.14148588 3272.83384068 -3009.89051515 -8557.27433151]\n", + "\n", + "=== Statistiques des scores de décision ===\n", + "Nombre total de scores: 60000\n", + "Score minimum: -122128.9854\n", + "Score maximum: 33569.8437\n", + "Score moyen: -12893.4394\n", + "Écart-type: 11346.1342\n", + "\n", + "=== Répartition selon le seuil par défaut (0) ===\n", + "Scores positifs (> 0): 5233 - Prédits comme '5'\n", + "Scores négatifs (≤ 0): 54767 - Prédits comme 'Non-5'\n", + "Pourcentage de scores positifs: 8.72%\n", + "Pourcentage de scores négatifs: 91.28%\n", + "\n", + "=== Vérification de cohérence ===\n", + "Les prédictions binaires (score > 0) correspondent aux prédictions précédentes: False\n", + "\n", + "=== Conclusion ===\n", + "Les scores de décision permettent de comprendre la 'confiance' du modèle:\n", + "• Plus le score est élevé, plus le modèle est confiant que c'est un '5'\n", + "• Plus le score est faible (négatif), plus le modèle est confiant que ce n'est PAS un '5'\n", + "• Le seuil par défaut de 0 sépare les deux classes\n" + ] + } + ], + "source": [ + "from sklearn.model_selection import cross_val_predict\n", + "import numpy as np\n", + "\n", + "print(\"=== Calcul des scores de décision avec cross_val_predict ===\\n\")\n", + "\n", + "# Utiliser cross_val_predict avec method='decision_function' pour obtenir les scores\n", + "# Cette fonction retourne les scores de décision pour chaque échantillon lors de la validation croisée 3-fold\n", + "y_train_scores = cross_val_predict(sgd_classifier, X_train, y_train_5, cv=3, method='decision_function')\n", + "\n", + "print(f\"Type des scores: {type(y_train_scores)}\")\n", + "print(f\"Forme des scores: {y_train_scores.shape}\")\n", + "print(f\"Type des éléments: {type(y_train_scores[0])}\")\n", + "\n", + "# Afficher quelques exemples de scores\n", + "print(f\"\\nPremiers 20 scores: {y_train_scores[:20]}\")\n", + "print(f\"Derniers 20 scores: {y_train_scores[-20:]}\")\n", + "\n", + "# Statistiques des scores\n", + "print(f\"\\n=== Statistiques des scores de décision ===\")\n", + "print(f\"Nombre total de scores: {len(y_train_scores)}\")\n", + "print(f\"Score minimum: {y_train_scores.min():.4f}\")\n", + "print(f\"Score maximum: {y_train_scores.max():.4f}\")\n", + "print(f\"Score moyen: {y_train_scores.mean():.4f}\")\n", + "print(f\"Écart-type: {y_train_scores.std():.4f}\")\n", + "\n", + "# Compter les scores positifs et négatifs (seuil par défaut = 0)\n", + "scores_positifs = np.sum(y_train_scores > 0)\n", + "scores_negatifs = np.sum(y_train_scores <= 0)\n", + "\n", + "print(f\"\\n=== Répartition selon le seuil par défaut (0) ===\")\n", + "print(f\"Scores positifs (> 0): {scores_positifs} - Prédits comme '5'\")\n", + "print(f\"Scores négatifs (≤ 0): {scores_negatifs} - Prédits comme 'Non-5'\")\n", + "print(f\"Pourcentage de scores positifs: {(scores_positifs / len(y_train_scores) * 100):.2f}%\")\n", + "print(f\"Pourcentage de scores négatifs: {(scores_negatifs / len(y_train_scores) * 100):.2f}%\")\n", + "\n", + "# Comparaison avec les prédictions binaires précédentes\n", + "predictions_binaires = (y_train_scores > 0)\n", + "coherence = np.array_equal(predictions_binaires, y_train_pred)\n", + "print(f\"\\n=== Vérification de cohérence ===\")\n", + "print(f\"Les prédictions binaires (score > 0) correspondent aux prédictions précédentes: {coherence}\")\n", + "\n", + "print(f\"\\n=== Conclusion ===\")\n", + "print(\"Les scores de décision permettent de comprendre la 'confiance' du modèle:\")\n", + "print(\"• Plus le score est élevé, plus le modèle est confiant que c'est un '5'\")\n", + "print(\"• Plus le score est faible (négatif), plus le modèle est confiant que ce n'est PAS un '5'\")\n", + "print(\"• Le seuil par défaut de 0 sépare les deux classes\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0a4ec288", + "metadata": {}, "outputs": [], "source": [] }