Obisidian vault auto-backup: 29-09-2025 15:19:43 on . 1 files edited

This commit is contained in:
Félix MARQUET
2025-09-29 15:19:43 +02:00
parent 22ff555a16
commit 6a894ddbfc

View File

@@ -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: <class 'numpy.ndarray'>\n",
"Forme des scores: (60000,)\n",
"Type des éléments: <class 'numpy.float64'>\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": []
}