From cb36bf254331525ddb968b820f676ea9645f73f4 Mon Sep 17 00:00:00 2001 From: jsboige Date: Sun, 20 Sep 2026 22:39:33 +0200 Subject: [PATCH 01/15] =?UTF-8?q?fix(density,#17040):=20redressement=201.2?= =?UTF-8?q?=20NumPy=20=E2=80=94=206=20cellules=20Lecture=20supprimees?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 5 --- ...2-Manipulation_de_Donnees_avec_NumPy.ipynb | 224 +----------------- 1 file changed, 1 insertion(+), 223 deletions(-) diff --git a/MyIA.AI.Notebooks/ML/DataScienceWithAgents/01-PythonForDataScience/notebooks/1.2-Manipulation_de_Donnees_avec_NumPy.ipynb b/MyIA.AI.Notebooks/ML/DataScienceWithAgents/01-PythonForDataScience/notebooks/1.2-Manipulation_de_Donnees_avec_NumPy.ipynb index 50b96983ba..0c87328db1 100644 --- a/MyIA.AI.Notebooks/ML/DataScienceWithAgents/01-PythonForDataScience/notebooks/1.2-Manipulation_de_Donnees_avec_NumPy.ipynb +++ b/MyIA.AI.Notebooks/ML/DataScienceWithAgents/01-PythonForDataScience/notebooks/1.2-Manipulation_de_Donnees_avec_NumPy.ipynb @@ -216,36 +216,6 @@ "print(\"dtype :\", mon_array.dtype)" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**Lecture de la création et inspection d'un tableau** (cellule code[3]) :\n", - "\n", - "La cellule ci-dessus illustre les 4 opérations fondamentales sur un `ndarray` :\n", - "\n", - "1. **`np.array([1, 2, 3, 4, 5])`** : crée un tableau 1D à partir d'une liste\n", - " Python. Le `dtype` est inféré : `int64` sur Linux/Mac, `int32` sur Windows\n", - " (dépend de la plateforme — un piège classique de portabilité).\n", - "2. **`type(mon_array)`** : retourne `numpy.ndarray`. C'est l'identité du type —\n", - " toutes les opérations NumPy sont définies sur cet objet.\n", - "3. **`mon_array.shape`** : retourne `(5,)` — un tuple d'une dimension. Notez la\n", - " virgule : c'est un tuple 1D, pas une simple parenthèse.\n", - "4. **`mon_array.dtype`** : `int64` (ou `int32` sur Windows). Le type des éléments\n", - " est *figé* à la création ; pour changer, il faut créer un nouveau tableau.\n", - "\n", - "**Pourquoi le `dtype` est inféré à la création** : NumPy ne fait pas de\n", - "conversion implicite. Si on mélange `int` et `float`, NumPy *upcast* vers le\n", - "type le plus large (e.g. `int + float → float`). C'est une règle simple mais\n", - "utile pour comprendre pourquoi `np.array([1, 2, 3.0])` produit un tableau\n", - "`float64`.\n", - "\n", - "**Sortie attendue** : un message console montrant la version de NumPy, le\n", - "tableau, son type (`numpy.ndarray`), sa forme (`(5,)`) et son dtype.\n", - "\n", - "**Coût** : < 0.05 seconde (import + création + 4 inspections)." - ] - }, { "cell_type": "markdown", "id": "8900f682", @@ -447,40 +417,6 @@ "print(f\"Vitesse : x{t_boucle / t_vect:.0f} plus rapide en vectorise\")" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**Lecture de la mesure vectorisation** (cellule code[7]) :\n", - "\n", - "La cellule ci-dessus mesure le gain de performance de la vectorisation NumPy\n", - "sur un cas concret : la somme des entiers de 0 à 999 999.\n", - "\n", - "**Le protocole** :\n", - "\n", - "1. Une fonction `somme_boucle(n)` qui boucle en Python pur (`for i in range(n)`).\n", - "2. Une opération vectorisée `x.sum()` où `x = np.arange(N, dtype=np.int64)`.\n", - "3. Chronométrage avec `time.perf_counter()` (haute précision).\n", - "4. Calcul du rapport `t_boucle / t_vect`.\n", - "\n", - "**Pourquoi cette mesure est convaincante** : 1 million d'itérations d'une boucle\n", - "Python implique 1 million de dispatches dans l'interpréteur Python (lookup de\n", - "bytecode, gestion de la pile, etc.). L'opération vectorisée `x.sum()` fait *un\n", - "seul* appel C qui itère sur le tableau via BLAS/LAPACK.\n", - "\n", - "**Sortie attendue** : deux chronométrages et un rapport ~25 (dépend du CPU et\n", - "de la version de NumPy/BLAS). Sur un laptop moderne avec OpenBLAS, on observe\n", - "typiquement 50-100 ms pour la boucle et 2-5 ms pour la version vectorisée.\n", - "\n", - "**Le piège classique** : croire que la vectorisation est « magique ». Elle ne\n", - "l'est pas : c'est juste que le code C est ~25× plus rapide que l'interpréteur\n", - "Python pour cette opération. Le facteur dépend du type d'opération (les boucles\n", - "triviales ont un facteur plus élevé ; les opérations complexes ont un facteur\n", - "plus bas).\n", - "\n", - "**Coût** : < 1 seconde (2 chronométrages sur 1M éléments)." - ] - }, { "cell_type": "markdown", "id": "26106520", @@ -616,52 +552,6 @@ "print(\"m + row shape =\", (m + row).shape)" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**Lecture du broadcasting cas 1 + 2** (cellules code[9-10]) :\n", - "\n", - "Les deux premières cellules montrent les cas les plus courants du broadcasting :\n", - "\n", - "**Cas 1 (cellule code[9]) : scalaire + tableau**\n", - "\n", - "```python\n", - "a = np.arange(3) # forme (3,)\n", - "a + 10 # broadcasting scalaire -> forme (3,)\n", - "```\n", - "\n", - "Le scalaire `10` est *promu* à la forme `(3,)` avant l'addition. NumPy duplique\n", - "le scalaire pour chaque élément de `a`. C'est l'idiome pour ajouter un offset\n", - "constant à tout un tableau (centrage, normalisation, etc.).\n", - "\n", - "**Cas 2 (cellule code[10]) : vecteur ligne + matrice**\n", - "\n", - "```python\n", - "m = np.arange(6).reshape(2, 3) # forme (2, 3)\n", - "row = np.array([10, 20, 30]) # forme (3,)\n", - "m + row # broadcasting -> forme (2, 3)\n", - "```\n", - "\n", - "Le vecteur ligne `row` (forme `(3,)`) est diffusé à *chaque ligne* de la matrice\n", - "`m` (forme `(2, 3)`). Le résultat a la forme `(2, 3)` — chaque ligne de `m + row`\n", - "est `(m[i, :] + row)`. C'est l'idiome pour ajouter un offset par colonne (e.g.\n", - "bonus par matière à un tableau notes[étudiant, matière]).\n", - "\n", - "**L'alignement des formes (de droite à gauche)** :\n", - "\n", - "NumPy compare les formes *de la droite vers la gauche* :\n", - "- `(2, 3)` vs `(3,)` → aligner à droite → `(2, 3)` vs `(2, 3)`. La dimension\n", - " gauche du vecteur est implicitement 1, qui se diffuse à 2. Compatible.\n", - "- `(2, 3)` vs `(2,)` → `(2, 3)` vs `(2,)` → la dimension droite est 3 vs 2,\n", - " incompatible. NumPy lève `ValueError`.\n", - "\n", - "**Sortie attendue** : deux tableaux avec un offset constant (cas 1) ou un\n", - "vecteur ligne (cas 2) ajouté.\n", - "\n", - "**Coût** : < 0.01 seconde (2 opérations de broadcasting sur de petits tableaux)." - ] - }, { "cell_type": "code", "execution_count": 6, @@ -884,39 +774,6 @@ "print(\"X[[0, 2], [1, 3]] =\", X[[0, 2], [1, 3]], \" (paires (0,1) et (2,3))\")" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**Lecture de l'indexation** (cellule code[14]) :\n", - "\n", - "La cellule ci-dessus illustre les 3 idiomes d'indexation NumPy :\n", - "\n", - "1. **Tranches (slicing)** : `a[1:4]` retourne `[20, 30, 40]` (indices 1 à 3\n", - " exclus). Pour les matrices 2D, `X[:, 0]` retourne la colonne 0 (toutes les\n", - " lignes), `X[1:, 2:]` retourne un bloc en bas-droite.\n", - "2. **Indexation avancée** : `a[[0, 2, 4]]` retourne `[10, 30, 50]` (indices\n", - " piochés arbitrairement). Pour les matrices 2D, `X[[0, 2], [1, 3]]` retourne\n", - " un tableau 1D avec les éléments aux positions `(0, 1)` et `(2, 3)`.\n", - "3. **Masques booléens** : `a[a > 10]` retourne `[20, 30, 40, 50]` (les éléments\n", - " où `a > 10` est True). Le masque est lui-même un `ndarray` de booléens.\n", - "\n", - "**Pourquoi ces idiomes sont cruciaux** :\n", - "\n", - "- Les **tranches** sont la base de la manipulation de tableaux — `X[:, 0]` est\n", - " l'idiome pour « extraire la première colonne » (utilisé dans 80% du code de\n", - " data science).\n", - "- L'**indexation avancée** permet de piocher arbitrairement (e.g. « donne-moi\n", - " les 5 échantillons avec les indices [12, 45, 78, 123, 456] »).\n", - "- Les **masques booléens** sont l'idiome de filtrage — `df[df['age'] > 18]`\n", - " en Pandas, `arr[arr > 10]` en NumPy.\n", - "\n", - "**Sortie attendue** : 4 tableaux affichés : `a[1:4] = [20, 30, 40]`,\n", - "`X[:, 0] = [0, 4, 8]`, `X[1:, 2:] = [[6, 7], [10, 11]]`, etc.\n", - "\n", - "**Coût** : < 0.01 seconde (3 idiomes × ~3 opérations chacun)." - ] - }, { "cell_type": "code", "execution_count": 10, @@ -1159,50 +1016,6 @@ " \" <- changera au prochain run\")" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**Lecture de la sémantique de `axis`** (cellule code[18]) :\n", - "\n", - "La cellule ci-dessus illustre la sémantique de `axis` pour les réductions\n", - "sur une matrice 2D de forme `(2, 3)` (2 lignes, 3 colonnes).\n", - "\n", - "**Le protocole** :\n", - "\n", - "1. `X = np.array([[1, 2, 3], [4, 5, 6]])` : matrice 2×3.\n", - "2. `X.sum()` : 21 (tous les éléments).\n", - "3. `X.sum(axis=0)` : `[5, 7, 9]` — écrase les *lignes*, donc le résultat a\n", - " la forme des colonnes `(3,)`. Chaque entrée est la somme d'une colonne.\n", - "4. `X.sum(axis=1)` : `[6, 15]` — écrase les *colonnes*, donc le résultat a\n", - " la forme des lignes `(2,)`. Chaque entrée est la somme d'une ligne.\n", - "\n", - "**L'intuition visuelle** : imaginez la matrice comme une grille :\n", - "\n", - "```\n", - "1 2 3\n", - "4 5 6\n", - "```\n", - "\n", - "`axis=0` veut dire « pour chaque colonne, additionne *verticalement* » :\n", - "- colonne 0 : 1 + 4 = 5\n", - "- colonne 1 : 2 + 5 = 7\n", - "- colonne 2 : 3 + 6 = 9\n", - "→ résultat : `[5, 7, 9]`\n", - "\n", - "`axis=1` veut dire « pour chaque ligne, additionne *horizontalement* » :\n", - "- ligne 0 : 1 + 2 + 3 = 6\n", - "- ligne 1 : 4 + 5 + 6 = 15\n", - "→ résultat : `[6, 15]`\n", - "\n", - "**Le piège classique** : penser `axis=0` = « lignes » et `axis=1` = « colonnes »\n", - "est *inverse*. NumPy suit la convention « axis est l'axe *écrasé* » : `axis=0`\n", - "écrase l'axe 0 (les lignes), donc les lignes sont agrégées et le résultat\n", - "garde la forme des colonnes.\n", - "\n", - "**Coût** : < 0.01 seconde (3 sommes sur 6 éléments)." - ] - }, { "cell_type": "markdown", "id": "0cf94d3a", @@ -1344,41 +1157,6 @@ " print(\"Exercice a completer : vectorisez ce calcul (carres_vectorises)\")" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**Lecture méthodologique des exercices** (introduction à code[27]) :\n", - "\n", - "Les trois exercices fondamentaux couvrent les 3 idiomes NumPy essentiels :\n", - "\n", - "1. **Exercice A — vectorisation** : remplacer une boucle `for` par une\n", - " opération vectorisée (`** 2`). C'est la *brique élémentaire* de performance.\n", - "2. **Exercice B — masques booléens composés** : `(a > 5) & (a < 20)`. C'est\n", - " l'idiome de filtrage le plus courant en data science.\n", - "3. **Exercice C — broadcasting scalaire** : `notes + 2`. C'est l'idiome de\n", - " normalisation (ajout d'un offset à toutes les valeurs).\n", - "\n", - "**Pourquoi cette progression** : elle reflète la hiérarchie des besoins en ML.\n", - "\n", - "- **Niveau 1 — Vectorisation** : comprendre que `arr ** 2` bat `for i ...`.\n", - "- **Niveau 2 — Masques** : savoir filtrer avec des conditions composées.\n", - "- **Niveau 3 — Broadcasting** : savoir appliquer une transformation à toutes\n", - " les dimensions d'un tableau.\n", - "\n", - "**Pièges classiques** :\n", - "\n", - "- **Vectorisation** : écrire `for i ...: arr[i] = ...` au lieu de `arr ** 2`.\n", - " La boucle bat l'idiome vectorisé.\n", - "- **Masques** : oublier les parenthèses — `(a > 5) & (a < 20)` est correct ;\n", - " `a > 5 & a < 20` est un bug silencieux.\n", - "- **Broadcasting** : utiliser `notes + np.array([2, 2, 2])` au lieu de\n", - " `notes + 2` — les deux fonctionnent, mais le scalaire est plus lisible.\n", - "\n", - "**Coût total** : < 5 secondes (vectorisation + masques + broadcasting sur de\n", - "petits tableaux)." - ] - }, { "cell_type": "markdown", "id": "82a46888", @@ -2056,4 +1834,4 @@ }, "nbformat": 4, "nbformat_minor": 5 -} +} \ No newline at end of file From 1033298839b788d4b8d2b0971da79e2c01792803 Mon Sep 17 00:00:00 2001 From: jsboige Date: Sun, 20 Sep 2026 22:40:25 +0200 Subject: [PATCH 02/15] =?UTF-8?q?fix(density,#17040):=20redressement=202.1?= =?UTF-8?q?=20Workflow=20ML=20=E2=80=94=203=20cellules=20Lecture=20supprim?= =?UTF-8?q?ees?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 5 --- .../02-ML-Cours/2.1-Workflow-ML.ipynb | 34 +------------------ 1 file changed, 1 insertion(+), 33 deletions(-) diff --git a/MyIA.AI.Notebooks/ML/DataScienceWithAgents/02-ML-Cours/2.1-Workflow-ML.ipynb b/MyIA.AI.Notebooks/ML/DataScienceWithAgents/02-ML-Cours/2.1-Workflow-ML.ipynb index eec2305269..5f70288521 100644 --- a/MyIA.AI.Notebooks/ML/DataScienceWithAgents/02-ML-Cours/2.1-Workflow-ML.ipynb +++ b/MyIA.AI.Notebooks/ML/DataScienceWithAgents/02-ML-Cours/2.1-Workflow-ML.ipynb @@ -259,16 +259,6 @@ "print(\"Proportion classe 1 - test : {:.3f}\".format((y_test == 1).mean()))" ] }, - { - "cell_type": "markdown", - "id": "ebc87b17", - "metadata": {}, - "source": [ - "### Lecture du résultat : pourquoi ces deux nombres méritent votre attention\n", - "\n", - "Les proportions de la classe 1 — **0,483 sur le train** et **0,480 sur le test** — sont presque identiques : c'est exactement l'effet recherché de `stratify=y`. Sans stratification, un tirage au hasard peut s'écarter de quelques points ; sur un jeu de test de 150 observations, deux points de pourcentage représentent trois exemples — peu ici. Mais sur une classe rare (1 % de fraudes, par exemple), un découpage non stratifié peut produire un jeu de test où la classe d'intérêt est quasi absente, et toute métrique calculée dessus devient un non-sens. La stratification est une assurance quasi gratuite contre ce risque d'échantillonnage : elle conserve dans chaque découpage la structure que le modèle doit apprendre ET celle sur laquelle il sera jugé." - ] - }, { "cell_type": "markdown", "id": "10000006", @@ -513,18 +503,6 @@ "print(sweep.loc[sweep['accuracy_test'].idxmax()])" ] }, - { - "cell_type": "markdown", - "id": "0151e132", - "metadata": {}, - "source": [ - "### Lecture du graphique : les ciseaux du surapprentissage\n", - "\n", - "La courbe d'accuracy **train** monte continûment et finit par atteindre 1,0 : un arbre assez profond mémorise chaque observation, bruit compris. La courbe **test** suit la même trajectoire au début, culmine autour de la **profondeur 4 (accuracy 0,827)**, puis plafonne voire régresse. L'écart qui s'ouvre entre les deux courbes — 0,914 contre 0,827 au sommet du test — est le surapprentissage rendu visible : le modèle gagne sur des exemples déjà vus sans gagner sur des exemples nouveaux.\n", - "\n", - "Deux précautions pour la suite. D'abord, l'argmax du test (exercice 2) est une estimation fragile : sur 150 observations de test, un point d'accuracy représente 1,5 exemple, et le voisinage de l'optimum est plat — la validation croisée (notebook **2.5**) remplacera ce jugement à décision unique par une moyenne sur plusieurs découpages. Ensuite, ce balayage a utilisé le jeu de test pour *choisir* l'hyperparamètre : en pratique, ce choix se fait sur un jeu de validation dédié, et le test ne sert qu'une seule fois, à la toute fin — sinon on optimise contre le juge." - ] - }, { "cell_type": "markdown", "id": "1000000c", @@ -789,16 +767,6 @@ "print(\" aucune statistique du test ne fuite dans l'entraînement.\")" ] }, - { - "cell_type": "markdown", - "id": "39883630", - "metadata": {}, - "source": [ - "### Lecture : 0,827 — exactement l'accuracy de l'arbre nu à profondeur 4\n", - "\n", - "Ce n'est pas une coïncidence, et c'est l'occasion d'une observation honnête : **un arbre de décision est insensible aux changements d'échelle**. Ses seuils de coupure se déplacent avec la mise à l'échelle, mais les partitions de l'espace des caractéristiques restent les mêmes — le `StandardScaler` ne change donc rien pour ce modèle précis. La valeur du `Pipeline` n'est pas ici un gain d'accuracy : c'est la **discipline**. Dès que le modèle deviendra sensible aux échelles (k-NN, régression régularisée, SVM dans les notebooks suivants), ce même pipeline garantira que le scaler est ajusté sur le train seul ; écrit à la main, le réflexe « scaler puis découper » laisserait la moyenne et l'écart-type du test contaminer l'entraînement — une fuite silencieuse qui gonfle l'accuracy mesurée." - ] - }, { "cell_type": "markdown", "id": "10000014", @@ -900,4 +868,4 @@ }, "nbformat": 4, "nbformat_minor": 5 -} +} \ No newline at end of file From efb7da8269be4a79772766137cbe809d06b44bb3 Mon Sep 17 00:00:00 2001 From: jsboige Date: Sun, 20 Sep 2026 22:41:21 +0200 Subject: [PATCH 03/15] =?UTF-8?q?fix(density,#17040):=20redressement=202.1?= =?UTF-8?q?1b=20Proximal=20Operators=20=E2=80=94=208=20cellules=20Lecture?= =?UTF-8?q?=20supprimees?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 5 --- ....11b-Proximal-Operators-From-Scratch.ipynb | 310 +----------------- 1 file changed, 1 insertion(+), 309 deletions(-) diff --git a/MyIA.AI.Notebooks/ML/DataScienceWithAgents/02-ML-Cours/2.11b-Proximal-Operators-From-Scratch.ipynb b/MyIA.AI.Notebooks/ML/DataScienceWithAgents/02-ML-Cours/2.11b-Proximal-Operators-From-Scratch.ipynb index 1941a2926e..80167b7e0c 100644 --- a/MyIA.AI.Notebooks/ML/DataScienceWithAgents/02-ML-Cours/2.11b-Proximal-Operators-From-Scratch.ipynb +++ b/MyIA.AI.Notebooks/ML/DataScienceWithAgents/02-ML-Cours/2.11b-Proximal-Operators-From-Scratch.ipynb @@ -129,44 +129,6 @@ "print('S_1(-2.0) =', prox_l1(np.array([-2.0]), 1.0)[0], ' (shrink signe preserve)')" ] }, - { - "cell_type": "markdown", - "id": "c131i1prox", - "metadata": {}, - "source": [ - "### Lecture des quatre cas limites\n", - "\n", - "La sortie imprime exactement les quatre regimes de l'operateur, et chacun se\n", - "recalcule de tete avec la formule `sign(x) * max(|x| - lambda, 0)` :\n", - "\n", - "| Entree | Lambda | Sortie | Regime |\n", - "|---|---:|---:|---|\n", - "| 0.5 | 0 | 0.5 | identite (lambda = 0) |\n", - "| -0.3 | 1 | -0.0 | zone morte (|x| < lambda) |\n", - "| 2.0 | 1 | 1.0 | shrinkage de |x| - lambda |\n", - "| -2.0 | 1 | -1.0 | shrinkage, signe conserve |\n", - "\n", - "Trois faits de la sortie meritent d'etre nommes.\n", - "\n", - "- **La zone morte est exacte, pas approximative.** `|-0.3| < 1` donne\n", - " `max(0.3 - 1, 0) = 0` : la coordonnee n'est pas « petite », elle est\n", - " exactement nulle. C'est cette propriete qui produit la parcimonie mesuree\n", - " plus bas (`|x|_0`), contrairement a une penalisation quadratique qui\n", - " rapproche de zero sans jamais l'atteindre.\n", - "- **Le `-0.0` imprime n'est pas une coquille** : `sign(-0.3) = -1` et\n", - " `max(0.3 - 1, 0) = 0.0`, donc le produit vaut `-0.0` en arithmetique IEEE.\n", - " Le signe de l'entree est conserve jusque dans l'annulation — aucun effet\n", - " sur les resultats numeriques, mais cela montre que le signe est applique\n", - " *apres* le seuillage.\n", - "- **Hors zone morte, l'operateur retranche exactement lambda** :\n", - " `|2.0| - 1 = 1`, et pour `-2.0` le signe negatif est preserve (`-1.0`).\n", - " Toute coordonnee retenue est donc biaisee de `lambda` vers zero.\n", - "\n", - "Ce dernier point est la raison d'etre du paragraphe suivant : le L1 echange\n", - "un biais systematique contre une parcimonie exacte, et c'est ce biais que le\n", - "choix de `lambda` va doser.\n" - ] - }, { "cell_type": "markdown", "id": "83840eba", @@ -426,52 +388,6 @@ "print(f'||bruit||_2 / ||b_clean||_2 = {np.linalg.norm(noise)/np.linalg.norm(b_clean):.4f}')" ] }, - { - "cell_type": "markdown", - "id": "c131i2regime", - "metadata": {}, - "source": [ - "### Carte d'identite de l'experience, et ce que le tirage dit deja\n", - "\n", - "Les quatre lignes de sortie fixent le regime complet. Le tableau les reprend,\n", - "avec les quantites derivees qui serviront a lire tous les resultats suivants :\n", - "\n", - "| Quantite | Valeur | Lecture |\n", - "|---|---:|---|\n", - "| Dimension du signal `p` | 500 | inconnues |\n", - "| Mesures `n` | 200 | equations |\n", - "| Ratio `n/p` | 0.40 | systeme 2.5x sous-determine |\n", - "| Support vrai `k` | 30 | densite 6.00 % |\n", - "| Bruit relatif `||e||_2 / ||A x*||_2` | 0.0204 | 2.04 % du signal |\n", - "| Graine `rng` | 42 | tirage reproductible |\n", - "\n", - "**La condition de comptage est confortable.** L'heuristique usuelle du\n", - "compressed sensing demande un nombre de mesures de l'ordre de `k log(p/k)` ;\n", - "ici `30 x log(500/30) = 30 x 2.81 = 84.4`, soit un budget de mesures 2.4 fois\n", - "superieur au seuil. On doit donc s'attendre a une recuperation de support tres\n", - "bonne (mesuree a `R = 0.933` plus bas) : l'experience teste un regime\n", - "*confortable*, pas la frontiere theorique ou la recuperation s'effondre.\n", - "\n", - "**Le bruit tire n'est pas orthogonal au signal.** La sortie donne\n", - "`||b||_2 = 7.0591` et `||A x*||_2 = 7.0345`, soit un allongement de `0.0246`.\n", - "Or `||e||_2 = 0.0204 x 7.0345 = 0.1435`, et si `e` etait orthogonal a `A x*`\n", - "l'allongement attendu serait `||e||^2 / (2 ||A x*||) = 0.0206 / 14.07 =\n", - "0.0015`. L'allongement observe est **17 fois** cette prediction : il ne peut\n", - "donc pas venir du terme quadratique, il vient du produit scalaire\n", - "`2 = 0.3467 - 0.0206 = 0.3261` (en normes carrees), soit\n", - "`cos(A x*, e) ~ 0.16`. Pour `n = 200` coordonnees, un bruit independant\n", - "produit typiquement un alignement de `1/sqrt(n) = 0.07` : l'ecart observe\n", - "reste du meme ordre de grandeur. La lecon de lecture est nette : **un ecart de\n", - "normes entre `b` et `A x*` ne mesure pas la taille du bruit**, et ne doit pas\n", - "etre presente comme tel.\n", - "\n", - "**L'erreur des cellules suivantes est absolue.** Le script calcule\n", - "`err_L2 = ||x - x*||_2` (norme euclidienne, sans normalisation), et\n", - "`||x*||_2` n'est imprime nulle part : les `0.1316` qui reviennent dans tout le\n", - "notebook se lisent donc en valeur absolue, pas en pourcentage. Ce detail de\n", - "definition evite le contresens le plus courant sur ce genre de tableau.\n" - ] - }, { "cell_type": "code", "execution_count": 6, @@ -507,47 +423,6 @@ "print(f'lambda retenu = {lam:.4f} (5x theorique, robuste au bruit)')" ] }, - { - "cell_type": "markdown", - "id": "c131i3lambda", - "metadata": {}, - "source": [ - "### Verifier lambda, puis regarder ce que le facteur 5 achete\n", - "\n", - "La valeur theorique se recalcule exactement depuis les parametres affiches\n", - "plus haut, avec `lambda_th = sigma sqrt(2 log p) / sqrt(n)`, `sigma = 0.01`,\n", - "`p = 500`, `n = 200` :\n", - "\n", - "```\n", - "sqrt(2 log 500) = sqrt(12.4292) = 3.5255\n", - "3.5255 / sqrt(200) = 3.5255 / 14.1421 = 0.2493\n", - "lambda_th = 0.01 x 0.2493 = 0.00249\n", - "```\n", - "\n", - "Les `0.0025` imprimes concordent a l'arrondi d'affichage pres. Le facteur\n", - "`5.0` du code est explicite : `5 x 0.00249 = 0.01246`, que la sortie arrondit\n", - "a `0.0125`.\n", - "\n", - "**Ce que le facteur achete, et ce qu'il coute.** Multiplier le seuil par 5\n", - "deplace la zone morte a `0.0125` : toute coordonnee de magnitude inferieure\n", - "est annulee, et toute coordonnee retenue est biaisee de `0.0125`. C'est un\n", - "deplacement du curseur biais/variance — plus de parcimonie et moins de\n", - "variables parasites, au prix de coordonnees vraies perdues (le rappel mesure\n", - "plus bas vaut `0.933`, soit `28` supports vrais retrouves sur `30`). Le\n", - "notebook ne compare pas plusieurs valeurs de `lambda` : le tableau de synthese\n", - "decrit donc le comportement de l'estimateur **a ce lambda-la**, et non une\n", - "propriete generale du Lasso.\n", - "\n", - "**Defaut preexistant signale (non corrige).** Le commentaire de la cellule\n", - "annonce `lambda ~ sigma * sqrt(2 log p) / n`, division par `n`, alors que le\n", - "code calcule `/ np.sqrt(n)`, division par `sqrt(n)`. Les deux formules\n", - "different d'un facteur `sqrt(200) = 14.1` : le commentaire, applique tel quel,\n", - "donnerait `0.00018` et non `0.0025`. C'est la version du code qui est imprimee\n", - "et qui est utilisee. Ce grain s'interdit de modifier la cellule code (sa\n", - "preuve est « cellule byte-identique »), donc l'ecart est signale ici et dans\n", - "la description de la PR, pour une correction dediee.\n" - ] - }, { "cell_type": "code", "execution_count": 7, @@ -597,48 +472,6 @@ " f'|x|_0 = {nz}, temps = {t:.3f}s')" ] }, - { - "cell_type": "markdown", - "id": "c131i4istafista", - "metadata": {}, - "source": [ - "### ISTA et FISTA : meme solution, et une acceleration non mesuree ici\n", - "\n", - "Les deux methodes from scratch affichent des metriques **identiques au\n", - "quatrieme decimal** :\n", - "\n", - "```\n", - "ISTA : err_L2 = 0.1316, P = 0.308, R = 0.933, |x|_0 = 91, 0.174 s\n", - "FISTA : err_L2 = 0.1316, P = 0.308, R = 0.933, |x|_0 = 91, 0.137 s\n", - "```\n", - "\n", - "Trois lectures s'en deduisent, dans cet ordre de solidite.\n", - "\n", - "1. **L'accord est quantitatif, pas qualitatif.** Meme erreur, meme precision,\n", - " meme rappel, meme nombre de coordonnees retenues au seuil numerique\n", - " `1e-6`. Les deux methodes resolvent le meme probleme convexe et rendent le\n", - " meme optimum ; la seule difference observable est le temps.\n", - "2. **Le gain de Nesterov se lit a `-21 %` sur le temps, pas en ordres de\n", - " grandeur** : `0.137 / 0.174 = 0.787`. C'est coherent avec le fait que FISTA\n", - " paye une operation vectorielle de plus par iteration (la mise a jour\n", - " d'inertie) et que les deux algorithmes sont arretes par le meme critere\n", - " (`tol = 1e-8`, plafond `2000` iterations) sur un probleme deja bien\n", - " conditionne.\n", - "3. **Le nombre d'iterations n'est imprime nulle part.** Or c'est la seule\n", - " grandeur qui permettrait de verifier l'acceleration `O(1/k^2)` annoncee\n", - " dans la synthese : `0.174 s` et `0.137 s` sont des temps, et un temps n'est\n", - " pas un nombre d'iterations (les deux methodes n'ont pas le meme cout par\n", - " iteration). **La phrase « FISTA obtient le meme ecart a l'optimum en ~k\n", - " fois moins d'iterations que ISTA » n'est donc adossee a aucune valeur\n", - " imprimee par le notebook.** Le panneau log-log de la figure suivante est le\n", - " seul element qui montre l'ecart, et il reste qualitatif.\n", - "\n", - "Le point 3 est un constat sur le notebook lui-meme, verifiable en relisant les\n", - "deux `print` : ni `len(hist_ista)` ni `len(hist_fista)` n'y figurent. Ajouter\n", - "cette mesure serait une extension utile, mais elle appartient a un grain qui\n", - "touche le code, pas a celui-ci.\n" - ] - }, { "cell_type": "code", "execution_count": 8, @@ -675,40 +508,6 @@ " f'P = {prec:.3f}, R = {rec:.3f}, |x|_0 = {nz}, temps = {t_sklearn:.3f}s')" ] }, - { - "cell_type": "markdown", - "id": "c131i5sklearn", - "metadata": {}, - "source": [ - "### sklearn : la meme solution, 25 fois plus vite\n", - "\n", - "Le coordinate descent de sklearn retrouve exactement le meme point :\n", - "\n", - "```\n", - "sklearn Lasso (coord. descent) : err_L2 = 0.1316, P = 0.308, R = 0.933, |x|_0 = 91, 0.007 s\n", - "```\n", - "\n", - "`0.174 / 0.007 = 24.9` : la bibliotheque est **25 fois plus rapide** que\n", - "l'ISTA from scratch, pour des metriques indiscernables a l'affichage. Ce que\n", - "le facteur ne dit pas :\n", - "\n", - "- les deux implementations ne payent pas la meme chose par iteration. ISTA\n", - " fait un produit matrice-vecteur et un produit transpose-vecteur par pas, et\n", - " calcule `||A||_2^2` une seule fois par une SVD ; le coordinate descent\n", - " travaille sur une colonne a la fois, ce qui est bien plus efficace quand la\n", - " solution est creuse ;\n", - "- le code passe `alpha = lam / n` et non `lam`, parce que sklearn minimise une\n", - " somme *moyennee*, `(1/(2n)) ||Ax - b||^2 + alpha ||x||_1`. C'est cette\n", - " correspondance exacte qui autorise a comparer les deux erreurs ; une erreur\n", - " de facteur `n = 200` sur `alpha` aurait rendu les deux solutions\n", - " incomparables sans que rien dans le notebook ne le signale ;\n", - "- ce que l'implementation from scratch achete n'est donc pas la vitesse mais\n", - " la **lisibilite de l'algorithme** : une boucle explicite, un historique\n", - " d'objectif (`hist_ista`) et un operateur proximal visible. La comparaison\n", - " suivante (cvxpy) pose la meme question a l'autre bout : que paye-t-on pour\n", - " la garantie de l'optimum global ?\n" - ] - }, { "cell_type": "code", "execution_count": 9, @@ -747,51 +546,6 @@ " f'P = {prec:.3f}, R = {rec:.3f}, |x|_0 = {nz}, temps = {t_cvxpy:.3f}s')" ] }, - { - "cell_type": "markdown", - "id": "c131i6cvxpy", - "metadata": {}, - "source": [ - "### cvxpy : la « verite terrain » a deux coordonnees de plus\n", - "\n", - "Le solveur SOCP donne la meme erreur et le meme rappel, mais **pas le meme\n", - "support** :\n", - "\n", - "```\n", - "ISTA / FISTA / sklearn : P = 0.308, R = 0.933, |x|_0 = 91\n", - "cvxpy CLARABEL : P = 0.301, R = 0.933, |x|_0 = 93\n", - "```\n", - "\n", - "**L'arithmetique ferme exactement.** Le vrai support compte `k = 30` entrees.\n", - "Un rappel de `0.933` correspond a `0.933 x 30 = 27.99`, soit `28` supports\n", - "vrais retrouves sur 30. Les precisions se recomposent alors sans reste :\n", - "\n", - "```\n", - "28 / 91 = 0.3077 -> 0.308 (imprime par ISTA, FISTA, sklearn)\n", - "28 / 93 = 0.3011 -> 0.301 (imprime par cvxpy)\n", - "```\n", - "\n", - "Le rappel etant identique, l'ecart de precision vient uniquement du\n", - "denominateur : le solveur exact selectionne `93 - 91 = 2` coordonnees\n", - "supplementaires, **toutes deux fausses**. Sur les 500 colonnes candidates, la\n", - "solution L1 retient donc `28` vraies et `91 - 28 = 63` fausses : un estimateur\n", - "a fort rappel et faible precision, ou les fausses decouvertes sont `2.25` fois\n", - "plus nombreuses que les vraies.\n", - "\n", - "**Consequence de lecture :** qualifier cvxpy de « verite terrain » vaut pour\n", - "la **valeur de l'objectif** — c'est bien l'optimum global du probleme convexe —\n", - "mais pas pour le **support** ; sur ce critere, le solveur exact est legerement\n", - "*moins* precis que l'ISTA from scratch. Confondre les deux registres serait\n", - "l'erreur d'interpretation naturelle de ce tableau.\n", - "\n", - "**L'ecart de temps final** vaut `0.735 / 0.007 = 105`. Du plus rapide au plus\n", - "lent, un facteur 105 separe deux solveurs qui rendent la meme erreur a quatre\n", - "decimales. C'est la mesure la plus nette du notebook : sur ce regime,\n", - "**l'erreur est une propriete de l'estimateur et du choix de lambda, pas de\n", - "l'algorithme**. Ce qui change d'un solveur a l'autre, c'est le support et le\n", - "temps.\n" - ] - }, { "cell_type": "code", "execution_count": 10, @@ -842,37 +596,6 @@ "plt.show()" ] }, - { - "cell_type": "markdown", - "id": "c131i7figure", - "metadata": {}, - "source": [ - "### Ce que la figure montre, et le raccourci qu'elle prend\n", - "\n", - "Le panneau gauche trace l'objectif `f(x^k)` en echelle lineaire, le panneau\n", - "droit le meme ecart en log-log. Deux points de methode avant d'y lire une\n", - "acceleration.\n", - "\n", - "- **L'axe vertical du panneau droit n'est pas l'ecart a l'optimum exact.** Le\n", - " code trace `hist - hist[-1] + 1e-12` : la derniere valeur atteinte sert de\n", - " substitut a `f(x*)`, qui n'est pas connu analytiquement ici. Le procede est\n", - " legitime — les deux methodes rendent le meme point, donc leur `hist[-1]`\n", - " coincide a la precision affichee — mais la pente lue a droite de la figure\n", - " est celle de l'ecart a *cette* reference, pas a l'optimum du probleme. Le\n", - " plancher `1e-12` evite le logarithme de zero.\n", - "- **La figure ne remplace pas un compteur d'iterations.** Les deux courbes\n", - " partagent le meme axe `k`, mais aucun des deux runs n'imprime son nombre\n", - " d'iterations effectives ; la comparaison des pentes reste donc un argument\n", - " qualitatif, coherent avec la theorie `O(1/k)` contre `O(1/k^2)`\n", - " (Beck & Teboulle 2009), et non une verification chiffree.\n", - "\n", - "C'est le partage que ce notebook permet de faire, et il vaut la peine d'etre\n", - "dit : l'accord **quantitatif** des quatre solveurs est imprime (erreurs,\n", - "supports, temps), tandis que l'**acceleration** de FISTA reste visible sur la\n", - "figure sans etre chiffree. Une lecture honnete ne transfere pas la solidite de\n", - "l'un vers l'autre.\n" - ] - }, { "cell_type": "markdown", "id": "8db42684", @@ -910,37 +633,6 @@ "" ] }, - { - "cell_type": "markdown", - "id": "c131i8table", - "metadata": {}, - "source": [ - "### Lecture du tableau : quatre solveurs, un seul estimateur\n", - "\n", - "Le tableau se lit en separant deux colonnes qui ne mesurent pas la meme chose.\n", - "\n", - "- **`err L2 vs x*` est l'erreur de l'estimateur.** Elle vaut `0.1316` pour les\n", - " quatre solveurs, a quatre decimales. Ce n'est pas une coincidence numerique :\n", - " le probleme Lasso est convexe, ses quatre formulations (forward-backward,\n", - " forward-backward accelere, coordinate descent, SOCP) ont le meme ensemble de\n", - " solutions, et a `lambda` fixe elles rendent le meme point. La constante\n", - " `0.1316` est donc le **biais du choix de lambda** (`5 x` la valeur\n", - " theorique), pas la signature d'un algorithme.\n", - "- **`|x|_0` et `P` sont les colonnes qui discriminent.** Elles separent le\n", - " groupe `91 / 0.308` (ISTA, FISTA, sklearn) du `93 / 0.301` (cvxpy) sans que\n", - " l'erreur bouge. Une comparaison de solveurs qui ne regarderait que l'erreur\n", - " concluerait a tort a leur equivalence parfaite.\n", - "- **`Temps` varie d'un facteur `105`** (`0.735 s` contre `0.007 s`) pour une\n", - " erreur identique : le critere de choix entre ces implementations n'est jamais\n", - " l'erreur, il est le couple (support, temps).\n", - "\n", - "Enfin, la colonne `Temps` mesure un **temps mural**, pas un nombre\n", - "d'iterations : elle depend de la machine, de la charge et des appels BLAS.\n", - "Entre deux executions de ce notebook, `0.174 s` peut bouger sensiblement,\n", - "alors que `err_L2 = 0.1316` et `|x|_0 = 91` sont reproductibles (graine `42`).\n", - "Un tableau de synthese qui melange les deux registres doit le dire.\n" - ] - }, { "cell_type": "markdown", "id": "8cc5f8dc", @@ -1153,4 +845,4 @@ }, "nbformat": 4, "nbformat_minor": 5 -} +} \ No newline at end of file From 52f070c5801455e301f133404db88ec203a96a00 Mon Sep 17 00:00:00 2001 From: jsboige Date: Sun, 20 Sep 2026 22:41:34 +0200 Subject: [PATCH 04/15] =?UTF-8?q?fix(density,#17040):=20redressement=202.2?= =?UTF-8?q?=20Descente=20de=20gradient=20=E2=80=94=204=20cellules=20Lectur?= =?UTF-8?q?e=20supprimees?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 5 --- .../2.2-Descente-de-gradient.ipynb | 46 +------------------ 1 file changed, 1 insertion(+), 45 deletions(-) diff --git a/MyIA.AI.Notebooks/ML/DataScienceWithAgents/02-ML-Cours/2.2-Descente-de-gradient.ipynb b/MyIA.AI.Notebooks/ML/DataScienceWithAgents/02-ML-Cours/2.2-Descente-de-gradient.ipynb index dbdaffd04e..60d3520bd4 100644 --- a/MyIA.AI.Notebooks/ML/DataScienceWithAgents/02-ML-Cours/2.2-Descente-de-gradient.ipynb +++ b/MyIA.AI.Notebooks/ML/DataScienceWithAgents/02-ML-Cours/2.2-Descente-de-gradient.ipynb @@ -479,16 +479,6 @@ "plt.show()\n" ] }, - { - "cell_type": "markdown", - "id": "fa83b2c3", - "metadata": {}, - "source": [ - "### Lecture des deux panneaux : une descente rapide, puis un plateau\n", - "\n", - "Le panneau de gauche (échelle **log** sur l'axe vertical) raconte les deux phases typiques d'une descente de gradient : une chute brutale des premières itérations — chaque pas quitte une zone de forte pente et divise le coût par un facteur visible même en log — puis un long plateau où le gradient, devenu petit, n'offre plus qu'une pente faible à suivre. C'est un compromis explicite : **les dernières décimales coûtent presque autant d'itérations que les premières magnitude**. Le panneau de droite montre l'aboutissement : la droite `y = 47,12·x + 5,32` traverse le nuage — deux paramètres seulement, ajustés itération après itération sans jamais résoudre d'équation." - ] - }, { "cell_type": "markdown", "id": "7e626310", @@ -568,18 +558,6 @@ "# Le courbe \"trop grand\" explose (puis devient inf/nan -> non tracee apres divergence).\n" ] }, - { - "cell_type": "markdown", - "id": "7b6d06ae", - "metadata": {}, - "source": [ - "### Lecture : trois destins d'un même algorithme\n", - "\n", - "Les trois courbes incarnent les trois régimes d'un même mécanisme. Avec `lr = 0,001`, la descente **rampe** : le pas est si petit qu'après 100 itérations le coût a à peine bougé — l'algorithme est correct mais économiquement absurde. Avec `lr = 0,05`, le coût plonge immédiatement vers le minimum — le régime utile. Avec `lr = 1,5`, la courbe **explose** : chaque pas dépasse le minimum de si loin qu'il repart de plus haut — l'erreur s'amplifie à chaque itération au lieu de se réduire, signature d'une divergence géométrique.\n", - "\n", - "Le commentaire du code explique pourquoi 1,5 précisément : sur ces données, le gradient en `w` a une pente de l'ordre de `2·x² ≈ 2`, donc tout `lr` au-delà de `~1,0` fait overshooter. La leçon générale : **le learning rate admissible dépend de la courbure du coût** (des données), pas d'une règle universelle — d'où les optimiseurs adaptatifs (Adam, notebook **3.x**) qui ajustent le pas paramètre par paramètre, et les *schedules* qui commencent grand puis ralentissent." - ] - }, { "cell_type": "markdown", "id": "753ebdc9", @@ -710,18 +688,6 @@ "# GD converge vers la meme solution car les deux minimisent la MSE sur un cout convexe.\n" ] }, - { - "cell_type": "markdown", - "id": "5aa4ebf8", - "metadata": {}, - "source": [ - "### Lecture : 0,0124 d'écart — deux chemins, un même minimum\n", - "\n", - "`sklearn` résout les **équations normales** en une passe algébrique exacte ; notre descente s'en approche à `|Δw| = 0,0124` et `|Δb| = 0,0055` près. Pourquoi cet accord est-il garanti ici, et seulement ici ? Le coût MSE d'une régression linéaire est **convexe** : un seul minimum, aucune possibilité pour la descente de s'arrêter dans un faux plat local. Encore plus d'itérations resserreraient l'écart arbitrairement — le résidu restant mesure la précision choisie, pas une limite de la méthode.\n", - "\n", - "Alors pourquoi s'embêter à itérer ? Parce que la solution analytique ne survit pas au-delà de ce cas : une régression logistique, un réseau de neurones n'ont **pas de forme fermée**, et l'inversion matricielle des équations normales coûte `O(n³)` en nombre de caractéristiques — rédhibitoire en grande dimension. La descente de gradient est la méthode *générale* ; les équations normales, le raccourci d'un cas particulier." - ] - }, { "cell_type": "markdown", "id": "7061be47", @@ -824,16 +790,6 @@ "plt.show()\n" ] }, - { - "cell_type": "markdown", - "id": "5ce8b826", - "metadata": {}, - "source": [ - "### Lecture de la figure : vallée allongée contre bol rond\n", - "\n", - "Sans standardisation, la courbe de coût descend **lentement et par à-coups** : la caractéristique multipliée par 100 produit un gradient dominant dans sa direction, et chaque pas — calibré pour la pente la plus forte — sous-utilise l'autre direction ; la trajectoire zigzague au fond d'une vallée allongée au lieu de filer vers le minimum. Avec `StandardScaler`, les deux directions contribuent à parts comparables : la surface devient un bol presque rond, et le même `lr` emprunte un chemin direct. L'exercice 3 quantifie ce contraste en comptant les itérations nécessaires pour atteindre une même perte cible — la standardisation, déjà rencontrée au notebook **2.1** comme discipline de pipeline, prend ici sa seconde justification : c'est un **accélérateur de convergence**." - ] - }, { "cell_type": "markdown", "id": "6e231ab1", @@ -999,4 +955,4 @@ }, "nbformat": 4, "nbformat_minor": 5 -} +} \ No newline at end of file From 2681487b9c3bb91da3ce06cc9cdc7ee2db7a3e3b Mon Sep 17 00:00:00 2001 From: jsboige Date: Sun, 20 Sep 2026 22:42:24 +0200 Subject: [PATCH 05/15] =?UTF-8?q?fix(density,#17040):=20redressement=202.3?= =?UTF-8?q?=20Regression=20lineaire=20logistique=20=E2=80=94=205=20cellule?= =?UTF-8?q?s=20Lecture=20chiffrees=20ajoutees=20par=20#16596=20supprimees?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 5 --- .../2.3-Regression-lineaire-logistique.ipynb | 52 +------------------ 1 file changed, 1 insertion(+), 51 deletions(-) diff --git a/MyIA.AI.Notebooks/ML/DataScienceWithAgents/02-ML-Cours/2.3-Regression-lineaire-logistique.ipynb b/MyIA.AI.Notebooks/ML/DataScienceWithAgents/02-ML-Cours/2.3-Regression-lineaire-logistique.ipynb index 74b04ecff6..c45c1bf489 100644 --- a/MyIA.AI.Notebooks/ML/DataScienceWithAgents/02-ML-Cours/2.3-Regression-lineaire-logistique.ipynb +++ b/MyIA.AI.Notebooks/ML/DataScienceWithAgents/02-ML-Cours/2.3-Regression-lineaire-logistique.ipynb @@ -164,16 +164,6 @@ "print(\"R^2 sur le jeu de test :\", r2_score(y_test, y_pred))" ] }, - { - "cell_type": "markdown", - "id": "lect23-01", - "metadata": {}, - "source": [ - "### Lecture du premier ajustement\n", - "\n", - "Les trois pentes estimées — **71,7 (x0), 22,0 (x1), 72,9 (x2)** — contre une ordonnée à l'origine de **3,41** : le modèle a récupéré des effets très inégaux, x0 et x2 portant chacun plus de trois fois le poids de x1. Le **R² = 0,912** sur le jeu de test dit que 91,2 % de la variance de la cible est expliquée par ces trois variables — le reste (8,8 %) est le bruit injecté à la génération, qu'aucun modèle ne peut rattraper : viser un R² de 1,0 sur ces données reviendrait à apprendre le bruit. À retenir dès maintenant : ce R² élevé ne dit **rien** de la validité des coefficients — la section 3bis montrera que multicollinéarité, résidus et points influents doivent passer **avant** toute interprétation." - ] - }, { "cell_type": "markdown", "id": "a1000005", @@ -259,16 +249,6 @@ "# A lire : residus centres sur 0, pas de courbe ni d'entonnoir visible." ] }, - { - "cell_type": "markdown", - "id": "lect23-02", - "metadata": {}, - "source": [ - "### Lecture du graphe des résidus\n", - "\n", - "Le diagramme se lit comme un test de structure : les résidus (écarts verticaux entre points et droite) doivent flotter **sans motif** autour de zéro. Un nuage en entonnoir (variance croissante), une courbure systématique ou un point isolé à forte amplitude sont autant de signaux que le modèle linéaire rate quelque chose — hétéroscédasticité, relation non linéaire, valeur atypique. Le panneau de droite (distribution des résidus) complète : à peu près symétrique et centrée, elle est compatible avec l'hypothèse d'erreurs gaussiennes qui fonde les intervalles de confiance d'OLS. Ces graphes coûtent trois lignes de code et répondent à des questions qu'aucun R² ne pose." - ] - }, { "cell_type": "markdown", "id": "a1000007", @@ -406,16 +386,6 @@ "# la valeur de son coefficient." ] }, - { - "cell_type": "markdown", - "id": "lect23-03", - "metadata": {}, - "source": [ - "### Lecture du tableau des coefficients\n", - "\n", - "Le tri par valeur absolue donne la hiérarchie des effets : **x2 (72,87) > x0 (71,71) > x1 (21,97)** — un rapport de 3,3 entre extrêmes. Chaque coefficient se lit comme l'effet moyen sur la cible d'une **augmentation d'une unité** de la variable, les autres étant tenues constantes : « toutes choses égales par ailleurs ». C'est ce pluriel qui est fragile : la section 3bis.1 montrera que si deux variables bougent ensemble (corrélation de 0,99), cette clause devient vide et les coefficients deviennent instables — le tableau ci-dessus n'est interprétable que si les diagnostics qui suivent sont au vert." - ] - }, { "cell_type": "markdown", "id": "a93559e9", @@ -890,16 +860,6 @@ "print(proba_exemple)" ] }, - { - "cell_type": "markdown", - "id": "lect23-04", - "metadata": {}, - "source": [ - "### Lecture des probabilités prédites\n", - "\n", - "La régression logistique ne rend pas des classes mais des **probabilités** : chaque ligne de la matrice donne P(classe 0) et P(classe 1), dont la somme vaut 1. Les cinq points de test couvrent toute la gamme : du **quasi-certain** (0,988 pour la classe 1 au quatrième point) à l'**indécis** (0,32 / 0,68 au premier, presque un pile-ou-face). Cette granularité est la richesse du modèle : c'est elle qui permettra, à l'exercice 2, de choisir un **seuil** de décision adapté au coût des erreurs, plutôt que d'accepter le seuil implicite 0,5 d'un `predict` qui masque tout l'audit." - ] - }, { "cell_type": "markdown", "id": "a100000d", @@ -1067,16 +1027,6 @@ "# C'est precisement pour cela que la regression logistique existe." ] }, - { - "cell_type": "markdown", - "id": "lect23-05", - "metadata": {}, - "source": [ - "### Lecture : OLS et MLE ne répondent pas à la même question\n", - "\n", - "La figure superpose deux ajustements des mêmes données binaires : la droite OLS traverse le nuage en tirant chaque prédiction vers la moyenne locale des 0 et des 1 — elle peut produire des valeurs **hors de [0, 1]** et traite chaque point avec le même poids, quelle que soit sa position. La courbe logistique, ajustée par maximum de vraisemblance (MLE), est **contrainte dans [0, 1]** et s'aplatit exactement là où les probabilités doivent saturer. Sur des données binaires, OLS reste un estimateur correct en espérance, mais MLE fournit des intervalles et des tests cohérents avec la nature 0/1 de la cible — c'est le prix de la bonne fonction de lien." - ] - }, { "cell_type": "markdown", "id": "a1000011", @@ -1490,4 +1440,4 @@ }, "nbformat": 4, "nbformat_minor": 5 -} +} \ No newline at end of file From 2fafa74bc1fdb09e8ca58b9636698057f36956de Mon Sep 17 00:00:00 2001 From: jsboige Date: Sun, 20 Sep 2026 22:43:22 +0200 Subject: [PATCH 06/15] =?UTF-8?q?fix(density,#17040):=20redressement=202.3?= =?UTF-8?q?b=20Naive=20Bayes=20=E2=80=94=203=20cellules=20guide=20exercice?= =?UTF-8?q?=20ajoutees=20par=20#16007=20supprimees?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 5 --- .../2.3b-Naive-Bayes-Generatif.ipynb | 32 +------------------ 1 file changed, 1 insertion(+), 31 deletions(-) diff --git a/MyIA.AI.Notebooks/ML/DataScienceWithAgents/02-ML-Cours/2.3b-Naive-Bayes-Generatif.ipynb b/MyIA.AI.Notebooks/ML/DataScienceWithAgents/02-ML-Cours/2.3b-Naive-Bayes-Generatif.ipynb index b9a707a7e0..a1f3b4948f 100644 --- a/MyIA.AI.Notebooks/ML/DataScienceWithAgents/02-ML-Cours/2.3b-Naive-Bayes-Generatif.ipynb +++ b/MyIA.AI.Notebooks/ML/DataScienceWithAgents/02-ML-Cours/2.3b-Naive-Bayes-Generatif.ipynb @@ -544,16 +544,6 @@ "print(\"Exercice 1 a completer : Multinomial NB de zero (voir code ci-dessus)\")" ] }, - { - "cell_type": "markdown", - "id": "8a3042c9", - "metadata": {}, - "source": [ - "### Ce que votre complétion doit produire — le guide de l'exercice 1\n", - "\n", - "Le Multinomial NB remplace les densités gaussiennes par des **comptages** : une distribution de probabilité sur les occurrences (mots, tokens, catégories) plutôt qu'un ajustement en cloche. Trois pièges classiques guident la complétion. D'abord, calculez les log-probabilités et sommez — le produit de milliers de probabilités inférieures à 1 sous-flotte en `float64` bien avant la fin du vocabulaire ; l'espace log est la pratique universelle, pas un raffinement. Ensuite, le **lissage de Laplace** (`+1` aux comptes, normalisation au vocabulaire `+V`) : sans lui, un mot absent du train attribue une probabilité nulle à toute la classe, où qu'il apparaisse — une seule observation invisible tuerait le verdict. Enfin, la contre-épreuve attendue : vos probabilités a posteriori doivent reproduire les prédictions de `sklearn.naive_bayes.MultinomialNB` exactement, comme la cellule 1.2 l'a fait pour le cas gaussien — la vérification vaut preuve, toujours." - ] - }, { "cell_type": "markdown", "id": "b81c29ba", @@ -611,16 +601,6 @@ "print(\"Exercice 2 a completer : ecart NB-LR a n=30 par dimension =\", ecart_d)" ] }, - { - "cell_type": "markdown", - "id": "b06092b7", - "metadata": {}, - "source": [ - "### Ce que vous devriez observer — le guide de l'exercice 2\n", - "\n", - "La théorie prédit un **amplificateur** : l'avantage génératif au petit `n` grandit avec la dimension. Comptez les paramètres — NB estime `2d` quantités (une moyenne, une variance par caractéristique), chacune depuis `n` observations ; la régression logistique estime `d` poids *conjointement*, chaque poids ne se stabilisant qu'avec assez d'observations couvrant les covariations. À `n = 30` fixé, monter `d` retire des degrés de liberté au discriminatif bien plus vite qu'au génératif : l'écart `NB − LR` devrait s'élargir avec `d` — avant de plafonner, car l'hypothèse d'indépendance impose à NB son propre plafond (le scénario B ci-dessus en est la démonstration : une fois la corrélation en bloc installée, plus de dimension n'aide plus NB, elle l'enfonce). Votre valeur `None` mesurée complètera la colonne manquante de cette histoire." - ] - }, { "cell_type": "markdown", "id": "d0280cc0", @@ -680,16 +660,6 @@ "print(f\"Exercice 3 a completer : (a) {reponse_a}, (b) {reponse_b}\")" ] }, - { - "cell_type": "markdown", - "id": "237b2f6c", - "metadata": {}, - "source": [ - "### La règle de tri practice — guide de l'exercice 3\n", - "\n", - "Les deux scénarios mesurés plus haut sont vos étalons de calibration. Le régime (a) — petit échantillon, caractéristiques peu corrélées — est le terrain du génératif : à `n = 15`, NB menait de `+0,065` (scénario A). Le régime (b) — corrélation structurelle forte — bascule la faveur dès `n = 30` vers le discriminatif (scénario B : `-0,003` puis `-0,022`). La théorie (Ng & Jordan, 2002) donne la charpente : NB atteint son optimum asymptotique *plus vite* en `n` mais *moins haut* ; la régression logistique converge *plus lentement* vers un plafond *supérieur*. En pratique : textes (features nombreuses, quasi indépendantes par nature, petits jeux annotés) → NB ; données tabulaires massives et corrélées → discriminatif. L'exercice vous fait trancher sur des jeux non étiquetés — chaque verdict doit citer le signal qui l'a motivé (la taille relative de `n` face à `d`, et la structure de corrélation), pas une intuition." - ] - }, { "cell_type": "markdown", "id": "297a4b03", @@ -750,4 +720,4 @@ }, "nbformat": 4, "nbformat_minor": 5 -} +} \ No newline at end of file From 2ca67d2bd432500b32a4c3f403a541369a77934a Mon Sep 17 00:00:00 2001 From: jsboige Date: Sun, 20 Sep 2026 22:43:36 +0200 Subject: [PATCH 07/15] =?UTF-8?q?fix(density,#17040):=20redressement=202.3?= =?UTF-8?q?d=20LDA=20QDA=20=E2=80=94=205=20cellules=20markdown=20transitio?= =?UTF-8?q?n=20ajoutees=20par=20#16603=20supprimees?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 5 --- .../2.3d-Modele-Gaussien-LDA-QDA.ipynb | 52 +------------------ 1 file changed, 1 insertion(+), 51 deletions(-) diff --git a/MyIA.AI.Notebooks/ML/DataScienceWithAgents/02-ML-Cours/2.3d-Modele-Gaussien-LDA-QDA.ipynb b/MyIA.AI.Notebooks/ML/DataScienceWithAgents/02-ML-Cours/2.3d-Modele-Gaussien-LDA-QDA.ipynb index a1ada6c568..46cebf7f3d 100644 --- a/MyIA.AI.Notebooks/ML/DataScienceWithAgents/02-ML-Cours/2.3d-Modele-Gaussien-LDA-QDA.ipynb +++ b/MyIA.AI.Notebooks/ML/DataScienceWithAgents/02-ML-Cours/2.3d-Modele-Gaussien-LDA-QDA.ipynb @@ -65,16 +65,6 @@ "plt.rcParams[\"figure.figsize\"] = (6, 4)\n" ] }, - { - "cell_type": "markdown", - "id": "lect23d-01", - "metadata": {}, - "source": [ - "### La question de ce notebook\n", - "\n", - "Quatre classifieurs — LDA, QDA, régression logistique, Naive Bayes — vont être confrontés aux **mêmes données**, et la seule chose qui variera est **l'hypothèse de covariance** des classes : partagée, propres, ou diagonale. La thèse à éprouver : le meilleur modèle n'est pas le plus flexible, mais **celui dont l'hypothèse colle à la réalité des données**. Chaque section apporte une pièce : le calcul exact de la frontière (§1-2), des régimes contrôlés où l'on sait quelle hypothèse est vraie (§3), la géométrie des frontières (§4), la qualité des probabilités (§5), et la limite en grande dimension (§6)." - ] - }, { "cell_type": "markdown", "id": "d302bff5", @@ -162,16 +152,6 @@ " return self.classes[np.argmax(self.linear_discriminant(X), axis=0)]\n" ] }, - { - "cell_type": "markdown", - "id": "lect23d-02", - "metadata": {}, - "source": [ - "### Ce que le « de zéro » achète ici\n", - "\n", - "Réimplémenter le LDA à la main plutôt que d'appeler `sklearn` transforme chaque choix invisible en décision explicite : **quel estimateur** pour la covariance partagée (empirique poolée), **quelle frontière** (l'hyperplan tiré du §1), **quels priors**. La cellule suivante comparera le résultat à `sklearn` — si les deux s'accordent, ce n'est pas une coincidence : c'est la preuve que la formule du §1 est bien ce que la bibliothèque calcule. Le « de zéro » n'est pas un exercice de style : c'est ce qui permet de dire *je sais ce que fait la boîte noire*." - ] - }, { "cell_type": "code", "execution_count": 3, @@ -273,16 +253,6 @@ "On compare sur les **mêmes splits et graines** [2.3](2.3-Regression-lineaire-logistique.ipynb) : LDA, QDA, logistique (linéaire), Naive Bayes (gaussien diagonal).\n" ] }, - { - "cell_type": "markdown", - "id": "lect23d-03", - "metadata": {}, - "source": [ - "### Le protocole avant les résultats\n", - "\n", - "Trois régimes synthétiques, un seul facteur manipulé : la structure de covariance. Régime A — covariances **identiques** entre classes (l'hypothèse LDA est vraie par construction) ; régime B — covariances **différentes** (elle est fausse) ; régime C — covariances différentes mais **très peu de points**. Chaque accuracy est moyennée sur **20 graines** avec son écart-type : une différence de moins d'un écart-type ne se lit pas comme un signal. C'est ce dispositif — facteur contrôlé, répétition, barre d'erreur — qui autorisera la lecture d'après à parler de *signature de l'hypothèse* et non de loterie d'un split chanceux." - ] - }, { "cell_type": "code", "execution_count": 4, @@ -597,16 +567,6 @@ "Deux modèles peuvent avoir **la même accuracy** mais des probabilités très différentes : l'un sera bien calibré (une prédiction à 70 % est correcte ~70 % du temps), l'autre non. [2.5](2.5-Biais-Variance-CV-ROC.ipynb) introduisait la courbe ROC ; ici on regarde la **fiabilité** (calibration) et la **matrice de confusion** — pas seulement le taux de bien classés.\n" ] }, - { - "cell_type": "markdown", - "id": "lect23d-04", - "metadata": {}, - "source": [ - "### Lire une courbe de fiabilité avant de la lire\n", - "\n", - "L'instrument de cette section : le **diagramme de fiabilité** et le **score de Brier**. Pour chaque bac de probabilité prédite (0-0.1, 0.1-0.2, …), on trace la fréquence *observée* de la classe positive contre la probabilité *prédite* : un modèle parfait suit la diagonale. Au-dessus de la diagonale il sous-estime, en dessous il surestime — et un modèle peut avoir une bonne accuracy tout en étant **systématiquement trop confiant**. Le Brier condense cette diagnose en un nombre : la moyenne des carrés des écarts entre probabilité prédite et réalisation (0/1) — plus bas est mieux, et un modèle confiant-qui-se-trompe y est lourdement pénalisé. Gardez les deux à l'œil sur les sorties qui suivent." - ] - }, { "cell_type": "code", "execution_count": 7, @@ -738,16 +698,6 @@ "QDA estime **une covariance complète par classe** : c'est `d(d+1)/2` paramètres par classe, contre `d` pour LDA (covariance partagée) et `d` pour Naive Bayes (diagonale). En dimension `d`, LDA a `O(d)` paramètres, QDA a `O(d²)`. Le coût explose — et dès que `n_c` devient du même ordre que `d`, `Σ_c` devient **singulière** (non inversible).\n" ] }, - { - "cell_type": "markdown", - "id": "lect23d-05", - "metadata": {}, - "source": [ - "### Ce que le diagnostic mesure avant de le voir\n", - "\n", - "La dernière expérience fixe le nombre de points par classe et fait croître la dimension `d` : 2, 5, 10, 20, 30. Pour chaque `d`, le tableau comptera les **paramètres** estimés par chaque modèle, leur **accuracy**, et un drapeau de **covariance singulière** — le moment exact où estimer une covariance de classe par classe devient impossible faute de points. C'est le talon d'Achille de QDA annoncé : chaque covariance propre coûte de l'ordre de `d²` paramètres, et l'inverse d'une matrice estimée sur trop peu de points n'existe plus. Regardez la colonne du drapeau tourner — c'est elle qui datéra l'effondrement." - ] - }, { "cell_type": "code", "execution_count": 8, @@ -1086,4 +1036,4 @@ }, "nbformat": 4, "nbformat_minor": 5 -} +} \ No newline at end of file From 163e0651590965592c6bd2d3bb77d381de7203f5 Mon Sep 17 00:00:00 2001 From: jsboige Date: Sun, 20 Sep 2026 22:44:32 +0200 Subject: [PATCH 08/15] =?UTF-8?q?fix(density,#17040):=20redressement=202.4?= =?UTF-8?q?=20Arbres=20Forets=20=E2=80=94=205=20cellules=20Lecture=20ajout?= =?UTF-8?q?ees=20par=20#16007=20supprimees?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 5 --- .../2.4-Arbres-Forets-Ensembles.ipynb | 56 +------------------ 1 file changed, 1 insertion(+), 55 deletions(-) diff --git a/MyIA.AI.Notebooks/ML/DataScienceWithAgents/02-ML-Cours/2.4-Arbres-Forets-Ensembles.ipynb b/MyIA.AI.Notebooks/ML/DataScienceWithAgents/02-ML-Cours/2.4-Arbres-Forets-Ensembles.ipynb index 3469b339cd..e33d2ad2f0 100644 --- a/MyIA.AI.Notebooks/ML/DataScienceWithAgents/02-ML-Cours/2.4-Arbres-Forets-Ensembles.ipynb +++ b/MyIA.AI.Notebooks/ML/DataScienceWithAgents/02-ML-Cours/2.4-Arbres-Forets-Ensembles.ipynb @@ -244,16 +244,6 @@ "# train ~ 1.0 : l'arbre a memorise l'echantillon d'entrainement (surapprentissage)." ] }, - { - "cell_type": "markdown", - "id": "5bdebbda", - "metadata": {}, - "source": [ - "### Lecture : 1,000 contre 0,918 — la mémorisation, sur données réelles cette fois\n", - "\n", - "L'arbre sans limite de profondeur atteint **1,000 en entraînement** : avec 398 exemples et aucune contrainte, il pousse ses feuilles jusqu'à la pureté — chaque feuille finit par contenir un lot d'exemples tous de même classe, souvent un seul. Le test plafonne à **0,918** : l'écart de 8 points est le même phénomène de ciseaux qu'au notebook **2.1**, mais sur des données cliniques réelles (30 mesures, classes 212/357 déséquilibrées vers « bénin »). Retenez l'ordre de grandeur : sur ce jeu, un modèle *naïf* prédisant systématiquement la classe majoritaire atteindrait déjà `357/569 ≈ 0,63` — l'arbre apporte un vrai gain, mais son excès de confiance en train ne se transfère pas." - ] - }, { "cell_type": "markdown", "id": "2a4c0007", @@ -354,16 +344,6 @@ "# axis-aligned qui epousent le bruit de l'echantillon." ] }, - { - "cell_type": "markdown", - "id": "058354dc", - "metadata": {}, - "source": [ - "### Lecture de la frontière : des couloirs à angle droit\n", - "\n", - "La frontière de décision d'un arbre est une succession de **bandes perpendiculaires aux axes** — chaque seuil (`feature_i ≤ t`) coupe l'espace par une droite parallèle aux autres axes, et les coupures s'empilent en régions rectangulaires. C'est à la fois sa force (aucune hypothèse de forme : une frontière en escalier épouse des régions que la régression logistique, avec sa droite unique, ne séparera jamais) et sa limite (une diagonale « oblique » naturelle doit être approchée par un escalier de coupures, coûteux en profondeur et instable — bouger une observation peut déplacer une coupure entière). En projetant sur 2 variables pour la visualisation, rappelez-vous aussi que l'arbre réel décide sur les 30 : la figure montre une *tranche* du phénomène, pas sa totalité." - ] - }, { "cell_type": "markdown", "id": "2a4c0009", @@ -494,16 +474,6 @@ "# que pour l'arbre seul (arbre) : la moyenne de 100 arbres reduit la variance." ] }, - { - "cell_type": "markdown", - "id": "4dced412", - "metadata": {}, - "source": [ - "### Lecture : 0,936 — la moyenne de 100 arbres surentraînés est *moins* surentraînée\n", - "\n", - "Chaque arbre de la forêt, tiré sur un bootstrap et un sous-ensemble de variables, est volontairement aussi excessif que l'arbre seul (accuracy train 1,000). Pourtant le vote des 100 gagne **2 points en test** (0,918 → 0,936). Le mécanisme : les erreurs de chaque arbre, décorrélées par les deux sources d'aléa, se compensent en partie au vote — la variance du modèle agrégé diminue comme l'erreur moyenne résiduelle des arbres, sans que le biais de la famille change. C'est le théorème de la sagesse des foules appliqué aux modèles : la condition n'est pas que chaque arbre soit bon, mais que leurs erreurs ne soient pas *les mêmes*. La contre-partie visible dans la section suivante : la frontière de la forêt reste en escalier, mais l'escalier est *lissé* — les couloirs bruyants de l'arbre seul deviennent des marches régulières." - ] - }, { "cell_type": "markdown", "id": "2a4c000d", @@ -664,18 +634,6 @@ "plt.show()" ] }, - { - "cell_type": "markdown", - "id": "dc1fd5f7", - "metadata": {}, - "source": [ - "### Lecture du podium : le règne des « worst » — et ses limites\n", - "\n", - "Les quatre variables en tête — *worst concave points* (0,159), *worst area* (0,147), *worst perimeter* (0,086), *worst radius* (0,079) — sont toutes des statistiques « worst » : la valeur **la plus extrême** mesurée sur la cellule, pas sa moyenne. Cliniquement parlant : un noyau globalement calme mais présentant *une* zone très concave est plus suspects qu'un noyau uniformément médiocre — l'information diagnostique vit dans les extrêmes. C'est un résultat interprétable, obtenu sans hypothèse médicale préalable.\n", - "\n", - "Deux précautions avant de sur-interpréter. Les importances par **diminution d'impureté** sont calculées sur le train : elles récompensent les variables qui *séparent le jeu d'entraînement*, pas nécessairement celles qui généralisent. Et des variables corrélées (périmètre, rayon et aire d'une même cellule sont géométriquement liés) se *partagent* le crédit : chaque coupure revient à celle que l'arbre a rencontrée en premier, les sœurs repartent avec presque rien — la vraie importance du trio « taille » est diluée dans trois podiums distincts. L'exercice 2 vous fait vérifier la lecture du podium ; la permutation d'importances (non traitée ici) lève la seconde réserve." - ] - }, { "cell_type": "markdown", "id": "2a4c0011", @@ -803,18 +761,6 @@ "print(f\"Boosting -- accuracy test : {acc_test_boosting:.3f}\")" ] }, - { - "cell_type": "markdown", - "id": "5cd3bade", - "metadata": {}, - "source": [ - "### Lecture : 0,947 — corriger les résidus plutôt que voter\n", - "\n", - "Sur cette découpe, l'échelle est nette : arbre seul **0,918** < forêt **0,936** < boosting **0,947**. Le mécanisme diffère radicalement du vote : le boosting construit les arbres **séquentiellement**, chaque arbre nouveau apprenant les *résidus* (les erreurs) du modèle courant — l'ensemble est une somme additive où chaque maillon corrige le précédent, là où la forêt fait tirer ses sommets en parallèle et moyenne. Résultat : là où la forêt réduit la **variance** sans toucher au biais, le boosting réduit le **biais** (et peut le sur-corriger : c'est le modèle des trois qui surapprend le plus vite quand on pousse le nombre d'estimateurs).\n", - "\n", - "La précaution d'usage : ces trois nombres viennent d'un **seul** découpage train/test (171 exemples de test) — un point d'accuracy y pèse 0,6 %, l'écart forêt/boosting (1,1 point) tient dans deux exemples. L'exercice 3 vous demande précisément cette comparaison propre ; la validation croisée du notebook **2.5** dira si l'échelle tient en moyenne." - ] - }, { "cell_type": "markdown", "id": "2a4c0015", @@ -975,4 +921,4 @@ }, "nbformat": 4, "nbformat_minor": 5 -} +} \ No newline at end of file From 5a54c64d4104ea1236deeadbbd4f2d3b8cf15bb1 Mon Sep 17 00:00:00 2001 From: jsboige Date: Sun, 20 Sep 2026 22:46:35 +0200 Subject: [PATCH 09/15] =?UTF-8?q?fix(density,#17040):=20redressement=202.5?= =?UTF-8?q?=20Biais=20Variance=20CV=20ROC=20=E2=80=94=207=20cellules=20Lec?= =?UTF-8?q?ture=20chiffrees=20ajoutees=20par=20#16594=20supprimees?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 5 --- .../2.5-Biais-Variance-CV-ROC.ipynb | 72 +------------------ 1 file changed, 1 insertion(+), 71 deletions(-) diff --git a/MyIA.AI.Notebooks/ML/DataScienceWithAgents/02-ML-Cours/2.5-Biais-Variance-CV-ROC.ipynb b/MyIA.AI.Notebooks/ML/DataScienceWithAgents/02-ML-Cours/2.5-Biais-Variance-CV-ROC.ipynb index cfdf224b7b..6ae0b63971 100644 --- a/MyIA.AI.Notebooks/ML/DataScienceWithAgents/02-ML-Cours/2.5-Biais-Variance-CV-ROC.ipynb +++ b/MyIA.AI.Notebooks/ML/DataScienceWithAgents/02-ML-Cours/2.5-Biais-Variance-CV-ROC.ipynb @@ -164,16 +164,6 @@ "print(f\"Classes (0 = malin, 1 = benin) dans y : {np.bincount(y)}\")" ] }, - { - "cell_type": "markdown", - "id": "lect25-01", - "metadata": {}, - "source": [ - "### Lecture du jeu de données\n", - "\n", - "Le tableau de contrôle fixe la géométrie du problème : **569 observations × 30 variables**, réparties en **398 lignes d'entraînement et 171 de test** (≈ 70/30), pour deux classes déséquilibrées — **212 tumeurs malignes (37,3 %)** contre **357 bénignes (62,7 %)**. Ce dernier chiffre pose la ligne de base de référence : un modèle trivial qui répondrait « bénin » à toutes les questions atteindrait **62,7 % d'accuracy** sans rien apprendre. Toute performance doit donc se lire au-dessus de ce plancher — et c'est précisément ce déséquilibre qui rendra l'accuracy insuffisante à la section 5, où faux négatifs et faux positifs ne coûtent pas la même chose." - ] - }, { "cell_type": "markdown", "id": "a50c0005", @@ -271,16 +261,6 @@ " print(f\"{nom:22s} | {acc_train:7.3f} | {acc_test:7.3f} | {acc_train - acc_test:7.3f}\")" ] }, - { - "cell_type": "markdown", - "id": "lect25-02", - "metadata": {}, - "source": [ - "### Lecture du comparatif train vs test\n", - "\n", - "Le tableau inverse l'intuition naïve : la **régression logistique, au score d'entraînement le plus faible (0,967), est la seule à dépasser 0,94 en test (0,942)**, tandis que les deux modèles au train parfait (1,000) régressent à 0,936 (forêt) et 0,918 (arbre profond). La colonne `ecart` chiffre le phénomène : **0,026 contre 0,064 et 0,082**, un rapport de 3,1 entre les extrêmes. Un train à 1,000 n'est pas une preuve de qualité mais la **signature d'une mémorisation** : le modèle récite les 398 exemples vus au lieu d'en extraire la règle. Détail à ne pas rater : le `ConvergenceWarning` signale que la régression logistique a plafonné à 1 000 itérations de lbfgs — son 0,967/0,942 est donc un **plancher**, pas sa valeur convergée." - ] - }, { "cell_type": "markdown", "id": "a50c0007", @@ -571,16 +551,6 @@ "print(f\"Stratifie : moyenne {cv_strat.mean():.3f} +/- {cv_strat.std():.3f}\")" ] }, - { - "cell_type": "markdown", - "id": "lect25-03", - "metadata": {}, - "source": [ - "### Lecture : pourquoi le k-fold naïf échoue sur les classes rares\n", - "\n", - "La colonne « naif » montre **2 plis sur 5 sans aucun positif** (plis 2 et 4 : zéro exemple de la classe rare en validation) — 40 % des mesures portent sur un jeu où la classe intéressante est absente, donc évaluent la bonne réponse à une question jamais posée. Le k-fold stratifié répartit 1, 1, 1, 1, 2 positifs : chaque pli voit la classe rare. Le gain se lit sur la dispersion : **écart-type 0,029 → 0,010**, divisé par trois à moyenne identique (0,970). Et c'est là le piège le plus instructif : avec 3,0 % de positifs, prédire systématiquement « négatif » rapporte 0,970 d'accuracy — **les deux moyennes collent au score trivial** ; seule la variance trahit laquelle des deux évaluations est digne de confiance." - ] - }, { "cell_type": "markdown", "id": "f4be6353", @@ -660,16 +630,6 @@ "print(f\"Ecart R2 (fuite quantifiee) : {s_naif.mean() - s_tss.mean():.3f}\")" ] }, - { - "cell_type": "markdown", - "id": "lect25-04", - "metadata": {}, - "source": [ - "### Lecture : la fuite temporelle quantifiée\n", - "\n", - "L'écart entre les deux lignes mesure le mensonge du découpage : **R² ≈ 0,990 en moyenne pour le split aléatoire, −2,566 pour `TimeSeriesSplit`**, soit une fuite de **3,556 points de R²** fabriquée par le seul choix du découpage. Le split aléatoire mélange passé et futur : pour chaque pli de validation, le modèle dispose d'observations **postérieures** à celles qu'il doit prédire — il interpole, il ne prévoit pas. `TimeSeriesSplit` l'oblige à extrapoler, et le R² **négatif** dit crûment que la prédiction est **pire que la moyenne constante** de la cible. Règle pratique : dès qu'existe un axe temporel (prix, capteurs, cohortes), le k-fold aléatoire n'est pas « approximatif » — il est **faux**, et l'écart ci-dessus en est la mesure." - ] - }, { "cell_type": "markdown", "id": "933edc6c", @@ -1109,16 +1069,6 @@ "plt.show()" ] }, - { - "cell_type": "markdown", - "id": "lect25-05", - "metadata": {}, - "source": [ - "### Lecture de la courbe ROC\n", - "\n", - "La figure se lit point par point : chaque point est un **seuil** de décision ; l'abscisse porte le taux de faux positifs (FPR), l'ordonnée le taux de vrais positifs (TPR). La **diagonale est la ligne du hasard** — un classifieur qui répond au pile-ou-face ; plus la courbe **colle au coin supérieur gauche** (FPR = 0, TPR = 1), plus le modèle ordonne correctement les exemples à ce seuil. Ce qui frappe ici : la courbe reste **au-dessus de la diagonale sur toute la plage**, signe que le signal est exploitable à n'importe quel seuil, pas seulement à 0,5. L'**AUC** — l'aire sous cette courbe, que l'exercice 5 mesure — résume le tout en un nombre : la probabilité qu'un exemple positif reçoive un score plus élevé qu'un négatif tiré au hasard." - ] - }, { "cell_type": "markdown", "id": "a50c0011", @@ -1277,16 +1227,6 @@ "print(\"des seuils plus bas (cf. courbe ROC).\")" ] }, - { - "cell_type": "markdown", - "id": "lect25-06", - "metadata": {}, - "source": [ - "### Lecture : le seuil comme décision d'application\n", - "\n", - "Passer le seuil de **0,5 à 0,3** ramène les **faux négatifs de 2 à 0** — les deux exemples positifs manqués sont rattrapés — **sans coût en faux positifs** (8 aux deux seuils) : le terme diagonal inférieur passe de 105 à **107 sur 107**. Cette dissymétrie du gain est la leçon centrale : dans une application où un faux négatif et un faux positif **n'ont pas le même coût** (une maladie manquée contre un examen complémentaire), aucun score global ne capture la différence — elle ne se lit que dans la matrice de confusion, seuil par seuil. Le seuil « optimal » n'est donc pas une réponse statistique mais une **décision d'application** : le rapport de coûts FN/FP appartient au domaine, pas au modèle. Que ce gain soit ici gratuit (0 faux positif supplémentaire) tient à la qualité du classifieur — sur un modèle plus faible, abaisser le seuil se serait payé." - ] - }, { "cell_type": "markdown", "id": "a50c0015", @@ -1422,16 +1362,6 @@ "plt.show()" ] }, - { - "cell_type": "markdown", - "id": "lect25-07", - "metadata": {}, - "source": [ - "### Lecture de la synthèse par validation croisée\n", - "\n", - "La validation croisée resserre le verdict du simple split : **régression logistique 0,953 ± 0,014, forêt aléatoire 0,956 ± 0,023, arbre profond 0,917 ± 0,024**. Deux lectures s'imposent. D'abord, l'écart de **0,003** entre forêt et régression logistique est **non concluant** : leurs intervalles à ±1 écart-type se recouvrent largement — à ce niveau, préférer la forêt revient à élire un bruit d'échantillon. Ensuite, l'arbre profond perd **3,6 points** de moyenne : c'est le modèle le plus expressif du trio et le plus pauvre en généralisation — la variance de mémorisation s'y paie en toutes lettres, confirmant la lecture du comparatif train/test. La régression logistique, à la dispersion la plus faible, s'impose comme candidat **robuste par défaut** ; la forêt ne se justifierait que si son avance survivait à une comparaison multi-graine." - ] - }, { "cell_type": "markdown", "id": "52174f4b", @@ -1598,4 +1528,4 @@ }, "nbformat": 4, "nbformat_minor": 5 -} +} \ No newline at end of file From d8b02747e3c2a50b62e0b23b2eae28e6d94aaf05 Mon Sep 17 00:00:00 2001 From: jsboige Date: Sun, 20 Sep 2026 22:47:24 +0200 Subject: [PATCH 10/15] =?UTF-8?q?fix(density,#17040):=20redressement=202.6?= =?UTF-8?q?=20Clustering=20KMeans=20PCA=20=E2=80=94=205=20cellules=20Lectu?= =?UTF-8?q?re=20chiffrees=20ajoutees=20par=20#16602=20supprimees?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 5 --- .../2.6-Clustering-KMeans-PCA.ipynb | 52 +------------------ 1 file changed, 1 insertion(+), 51 deletions(-) diff --git a/MyIA.AI.Notebooks/ML/DataScienceWithAgents/02-ML-Cours/2.6-Clustering-KMeans-PCA.ipynb b/MyIA.AI.Notebooks/ML/DataScienceWithAgents/02-ML-Cours/2.6-Clustering-KMeans-PCA.ipynb index 933e708492..d260a60f88 100644 --- a/MyIA.AI.Notebooks/ML/DataScienceWithAgents/02-ML-Cours/2.6-Clustering-KMeans-PCA.ipynb +++ b/MyIA.AI.Notebooks/ML/DataScienceWithAgents/02-ML-Cours/2.6-Clustering-KMeans-PCA.ipynb @@ -164,16 +164,6 @@ "plt.show()" ] }, - { - "cell_type": "markdown", - "id": "lect26-01", - "metadata": {}, - "source": [ - "### Lecture du jeu de données\n", - "\n", - "**1797 images de 64 pixels** : chaque chiffre manuscrit est une grille 8×8 aplatie en un vecteur de 64 intensités de gris — c'est ce que dit le `(1797, 64)` affiché, et pourquoi chaque ligne de X vit dans un espace à 64 dimensions. Les 10 classes (chiffres 0 à 9) sont à peu près équilibrées, environ 180 images chacune. Le point clé pour la suite : ces étiquettes existent dans le jeu de données, mais **le clustering ne les utilisera jamais** — elles ne serviront qu'à vérifier, a posteriori, si les groupes trouvés sans supervision coïncident avec les vrais chiffres. C'est ce protocole (apprendre sans les labels, évaluer avec) qui rend ce jeu de données un banc d'essai honnête du non-supervisé." - ] - }, { "cell_type": "markdown", "id": "26060005", @@ -235,16 +225,6 @@ " \"(le cluster 3 ne correspond pas forcement au chiffre 3).\")" ] }, - { - "cell_type": "markdown", - "id": "lect26-02", - "metadata": {}, - "source": [ - "### Lecture de la première expérience KMeans\n", - "\n", - "L'**inertie 1 165 256** est la somme des carrés des distances de chaque point au centre de son cluster : c'est la quantité que KMeans minimise, une mesure de compacité interne — plus elle est basse, plus les boules sont serrées. Le détail affiché juste après est le piège classique du non-supervisé : les labels de cluster sont **arbitraires**. Le cluster « 3 » de la sortie n'a aucun lien avec le chiffre 3 — l'algorithme numérote ses groupes selon l'ordre d'initialisation, pas selon notre sémantique. Toute correspondance cluster → chiffre demandera une étape d'alignement explicite (ce que fera la matrice de confusion de la section 5). Enfin, demander k=10 est déjà une hypothèse forte : nous savons qu'il y a 10 chiffres, mais en vraie donnée sans étiquette, choisir k serait tout le problème — c'est l'objet de la méthode du coude qui suit." - ] - }, { "cell_type": "markdown", "id": "26060007", @@ -325,16 +305,6 @@ "print(\"Un coude est visible autour de k=10, coherent avec les 10 chiffres.\")" ] }, - { - "cell_type": "markdown", - "id": "lect26-03", - "metadata": {}, - "source": [ - "### Lecture de la courbe du coude\n", - "\n", - "La courbe décroît vite puis s'aplatit : chaque cluster ajouté retire de l'inertie, mais avec un rendement décroissant. Le **coude** est le point où le gain marginal devient négligeable — payer un cluster de plus ne « serre » presque plus rien. Que ce coude émerge autour de k=10 est une information remarquable : l'algorithme, qui n'a jamais vu les étiquettes, retrouve de lui-même la structure des dix chiffres dans la donnée. C'est le message central du non-supervisé : la classe n'est pas une annotation magique, c'est une régularité de la donnée que la compacité seule suffit à révéler — au prix, ici, d'un œil sur la courbe pour trancher où s'arrêter." - ] - }, { "cell_type": "markdown", "id": "26060009", @@ -480,16 +450,6 @@ " \"la PCA non supervisée retrouve la structure connue.\")" ] }, - { - "cell_type": "markdown", - "id": "lect26-04", - "metadata": {}, - "source": [ - "### Lecture de la projection ACP\n", - "\n", - "Les deux premières composantes ne capturent que **28,5 %** de la variance : projeter 64 dimensions sur 2 en jette les sept dixièmes. Et pourtant le nuage montre déjà des regroupements — les classes les plus séparées dans l'espace original restent séparées après projection. C'est le compromis de l'ACP : c'est la **meilleure** projection linéaire possible (au sens de la variance conservée), mais elle reste linéaire — deux chiffres séparés par une frontière courbe dans l'espace original peuvent se chevaucher une fois aplatis. L'exigence des 95 % de l'exercice 2 mesurera exactement ce que coûte la compression : combien de directions faut-il garder pour ne presque rien perdre." - ] - }, { "cell_type": "markdown", "id": "2606000d", @@ -1090,16 +1050,6 @@ " print(\"La suite du notebook ne depend pas de cette cellule.\")" ] }, - { - "cell_type": "markdown", - "id": "lect26-05", - "metadata": {}, - "source": [ - "### Lecture : UMAP face à t-SNE\n", - "\n", - "Sur la comparaison à trois panneaux, UMAP sépare les dix groupes **et** préserve leur arrangement relatif — les clusters voisins en UMAP sont grosso modo voisins dans la donnée, là où t-SNE optimise les voisinages locaux sans garantie sur les distances entre groupes. Ce « respect de la structure globale » est la principale différence pratique entre les deux moteurs. Le warning affiché n'est pas une erreur : en fixant `random_state`, on demande une carte reproductible au prix du parallélisme (`n_jobs` ramené à 1) — un arbitrage assumé en pédagogie, à lever si la vitesse devient le critère. Enfin UMAP est typiquement plus rapide à taille égale, ce qui le rend plausible sur des jeux plus grands que ces 1797 points." - ] - }, { "cell_type": "markdown", "id": "6b7235a9", @@ -1862,4 +1812,4 @@ }, "nbformat": 4, "nbformat_minor": 5 -} +} \ No newline at end of file From 207ef08c95d9bebecb8082c42563c73f6173793b Mon Sep 17 00:00:00 2001 From: jsboige Date: Sun, 20 Sep 2026 22:48:06 +0200 Subject: [PATCH 11/15] =?UTF-8?q?fix(density,#17040):=20redressement=20Lab?= =?UTF-8?q?12b=20Sequential=20Orchestration=20=E2=80=94=205=20cellules=20'?= =?UTF-8?q?Lire'=20ajoutees=20par=20#16408=20supprimees?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 5 --- .../Lab12b-Sequential-Orchestration.ipynb | 97 ------------------- 1 file changed, 97 deletions(-) diff --git a/MyIA.AI.Notebooks/ML/DataScienceWithAgents/Track2-GoogleADK/Day5-DS-Star/Lab12b-Sequential-Orchestration.ipynb b/MyIA.AI.Notebooks/ML/DataScienceWithAgents/Track2-GoogleADK/Day5-DS-Star/Lab12b-Sequential-Orchestration.ipynb index 092c9bacfd..6888f894ca 100644 --- a/MyIA.AI.Notebooks/ML/DataScienceWithAgents/Track2-GoogleADK/Day5-DS-Star/Lab12b-Sequential-Orchestration.ipynb +++ b/MyIA.AI.Notebooks/ML/DataScienceWithAgents/Track2-GoogleADK/Day5-DS-Star/Lab12b-Sequential-Orchestration.ipynb @@ -101,25 +101,6 @@ "logging.getLogger(\"google_adk.google.adk.runners\").setLevel(logging.ERROR)\n" ] }, - { - "cell_type": "markdown", - "id": "f40e52e3", - "metadata": { - "papermill": { - "duration": 0.002667, - "end_time": "2026-09-16T13:56:24.076178", - "exception": false, - "start_time": "2026-09-16T13:56:24.073511", - "status": "completed" - }, - "tags": [] - }, - "source": [ - "### Lire la configuration attestée : quel moteur a produit ces sorties\n", - "\n", - "La sortie d'import fixe le paramètre d'expérience du notebook en trois lignes : `Provider actif : openrouter`, `Modele : openrouter/openai/gpt-4.1`, `Endpoint externe : True`. C'est l'attestation que tout ce qui suit — la chaîne de désignation, les réponses des spécialistes, le verdict final — est produit par un **vrai moteur LLM externe**, pas par un stub ou une réponse codée en dur : la même exécution sur une autre session pourra confronter ses sorties à celles-ci en connaissant le modèle exact. Le reste de la cellule est de la plomberie assumée : l'insertion de `..` au `sys.path` (les utilitaires de l'atelier) et le filtre ciblé d'un avertissement EXPÉRIMENTAL de la bibliothèque ADK — filtré par motif précis, pas en bloquant tous les warnings." - ] - }, { "cell_type": "markdown", "id": "269a3b8a", @@ -314,25 +295,6 @@ "print(resultat.response_text[:400])\n" ] }, - { - "cell_type": "markdown", - "id": "802c08d1", - "metadata": { - "papermill": { - "duration": 0.003507, - "end_time": "2026-09-16T13:56:41.865120", - "exception": false, - "start_time": "2026-09-16T13:56:41.861613", - "status": "completed" - }, - "tags": [] - }, - "source": [ - "### Lire le verdict final : une vérification affichée, pas réimprimée\n", - "\n", - "La réponse finale imprimée commence par `VERDICT : COHÉRENT` et statue que « l'exécution a correctement vérifié les dimensions du dataset et le profilage de base est conforme à la planification et à la fonction définie » — le verdict ÉVALUE les dimensions sans les ré-énumérer. Les chiffres **120 lignes × 8 colonnes** vivent dans la demande posée à la chaîne (source de la cellule : « Traite ce dataset de 120 lignes et 8 colonnes ») ; ce que la sortie prouve, elle, est double : l'exécuteur a invoqué l'outil de profilage (`Appels d'outils : ('dataset_profile',)`), et la réponse finale vient `du dernier désigné, verifier` — la parole finale appartient au plan, pas au hasard des tours. Ce que la sortie ne prouve PAS : d'où viennent exactement les mots du verdict — il ne réimprime ni les dimensions ni le profil ; l'affirmation de conformité est celle du vérificateur, lue telle quelle." - ] - }, { "cell_type": "markdown", "id": "972f711e", @@ -426,25 +388,6 @@ " \"(Lab 12c), le transfert était décidé par le modèle en cours de tour.\")\n" ] }, - { - "cell_type": "markdown", - "id": "f4661380", - "metadata": { - "papermill": { - "duration": 0.004557, - "end_time": "2026-09-16T13:56:45.525363", - "exception": false, - "start_time": "2026-09-16T13:56:45.520806", - "status": "completed" - }, - "tags": [] - }, - "source": [ - "### Lire le plan réduit en chiffres : deux mains, zéro outil, quatre agents\n", - "\n", - "La sortie compare trois compteurs : `Plan réduit : ('planner', 'verifier')`, `Désignation exécutée : ('planner', 'verifier')` — déclarité et exécution coïncident — et `Appels d'outils : aucun`. La lecture en creux est la plus instructive : la flotte instanciée compte **toujours quatre agents** (coder et executor existent, avec leurs instructions et leurs outils), mais seuls deux sont désignés — l'exécution constate leur absence par le compteur d'appels vide et le tuple de deux mains. Changer la stratégie d'une chaîne C4 = changer une donnée (le plan), jamais le code : c'est la démonstration chiffrée du contrat — et l'anti-miroir du handoff C5 du Lab 12c, où la séquence était décidée pendant le tour." - ] - }, { "cell_type": "markdown", "id": "183d6975", @@ -549,25 +492,6 @@ " \"chaînes (contre-garde C1).\")\n" ] }, - { - "cell_type": "markdown", - "id": "af39bdbd", - "metadata": { - "papermill": { - "duration": 0.002651, - "end_time": "2026-09-16T13:56:56.116178", - "exception": false, - "start_time": "2026-09-16T13:56:56.113527", - "status": "completed" - }, - "tags": [] - }, - "source": [ - "### Lire l'historique : sept messages, un agent qui triple, aucune fuite\n", - "\n", - "La sortie de la mémoire commune mérite un comptage exact : `Auteurs dans la chaîne A : ['user', 'planner', 'coder', 'executor', 'executor', 'executor', 'verifier']` — **sept messages**, et l'exécuteur apparaît **trois fois** : un agent désigné peut prendre plusieurs tours consécutifs dans une même étape du plan, l'ordre désigné n'est pas un plafond de un tour par main. Second point, l'isolation : `fuite = False` alors que la chaîne B a tourné juste après — et les demandes des deux chaînes sont distinctes par construction (source de la cellule — A : « Analyse confidentielle : 60 lignes, 4 colonnes. » ; B : « Question banale : 10 lignes, 2 colonnes. ») : même en poussant B juste après A, rien de la conversation de A n'a transité. Le garde mesure précisément la fuite du mot « confidentielle » dans les textes de B : le contre-garde C1 est mesuré, pas seulement affirmé." - ] - }, { "cell_type": "markdown", "id": "6f912ec4", @@ -763,27 +687,6 @@ "print(\"Exercice a completer\")\n" ] }, - { - "cell_type": "markdown", - "id": "8c667a0e", - "metadata": { - "papermill": { - "duration": 0.002551, - "end_time": "2026-09-16T13:56:56.180911", - "exception": false, - "start_time": "2026-09-16T13:56:56.178360", - "status": "completed" - }, - "tags": [] - }, - "source": [ - "### Lire les trois exercices : l'échelle des contre-contrats\n", - "\n", - "Les trois cellules d'exercice sont des stubs C.1 suivant le patron canonique du dépôt — chaque invite imprime « Exercice à compléter », aucune erreur volontaire — le notebook s'exécute d'un bout à l'autre, la validation est l'étudiant. L'échelle des énoncés prolonge la leçon : **Exercice 1** place un vérificateur en tête de plan — la question devient « que vérifie-t-on quand rien n'a encore été produit ? », l'ordre du plan comme décision d'architecture ; **Exercice 2** déplace le plan hors des instructions des agents — le même anti-pattern que le notebook vient de démontrer, à refaire tenir par construction ; **Exercice 3** demande un compteur de désignation — instrumenter `agent_hands` pour mesurer qui a pris la parole, l'observable du contrat C4. Trois gestes : inverser, encadrer, instrumenter.\n", - "\n", - "Dernière observation, sur la forme : chaque stub imprime l'invite canonique « Exercice à compléter » — le patron du dépôt pour une cellule d'exercice, qui la rend à la fois exécutable et informative : l'output atteste que la cellule a tourné, la place de la solution reste à l'étudiant. Partout ailleurs, chaque cellule de démonstration imprime son observable (le plan déclaré, les mains, les appels d'outils, l'historique) ; la zone d'exercice prend le relais exactement là où l'observable attendu devient celui de l'étudiant — et la conclusion ci-dessous referme le contrat C4 en rappelant ce que la désignation garantit que le handoff ne garantit pas." - ] - }, { "cell_type": "markdown", "id": "76b5c16f", From 337453c0a415e8371981a8bf49cd79ffde7d6647 Mon Sep 17 00:00:00 2001 From: jsboige Date: Sun, 20 Sep 2026 22:48:38 +0200 Subject: [PATCH 12/15] =?UTF-8?q?fix(density,#17040):=20redressement=20Lab?= =?UTF-8?q?12c=20Agent=20Handoff=20=E2=80=94=205=20cellules=20'Lire'=20ajo?= =?UTF-8?q?utees=20par=20#16408=20supprimees?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 5 --- .../Day5-DS-Star/Lab12c-Agent-Handoff.ipynb | 97 ------------------- 1 file changed, 97 deletions(-) diff --git a/MyIA.AI.Notebooks/ML/DataScienceWithAgents/Track2-GoogleADK/Day5-DS-Star/Lab12c-Agent-Handoff.ipynb b/MyIA.AI.Notebooks/ML/DataScienceWithAgents/Track2-GoogleADK/Day5-DS-Star/Lab12c-Agent-Handoff.ipynb index 35e1432579..b80a2f4797 100644 --- a/MyIA.AI.Notebooks/ML/DataScienceWithAgents/Track2-GoogleADK/Day5-DS-Star/Lab12c-Agent-Handoff.ipynb +++ b/MyIA.AI.Notebooks/ML/DataScienceWithAgents/Track2-GoogleADK/Day5-DS-Star/Lab12c-Agent-Handoff.ipynb @@ -94,25 +94,6 @@ "print(f\"Endpoint externe : {bool(provider.base_url)}\")\n" ] }, - { - "cell_type": "markdown", - "id": "6f5b2f7a", - "metadata": { - "papermill": { - "duration": 0.001996, - "end_time": "2026-09-16T13:57:24.912608", - "exception": false, - "start_time": "2026-09-16T13:57:24.910612", - "status": "completed" - }, - "tags": [] - }, - "source": [ - "### Lire la configuration attestée : le même moteur que la chaîne, pour comparer\n", - "\n", - "Comme dans le Lab 12b, la sortie d'import atteste le paramètre d'expérience : `Provider actif : openrouter`, `Modele : openrouter/openai/gpt-4.1`, `Endpoint externe : True`. Ce n'est pas une répétition gratuite : le Lab 12b (désignation C4) et celui-ci (handoff C5) comparent deux contrats **sur le même moteur** — c'est ce qui rend la comparaison honnête. Quand le §4 montrera la même intention réalisée par deux mécanismes distincts, la seule variable sera le contrat, pas le modèle." - ] - }, { "cell_type": "markdown", "id": "0572b2e0", @@ -195,25 +176,6 @@ " \"hierarchie existe.\")\n" ] }, - { - "cell_type": "markdown", - "id": "71916c53", - "metadata": { - "papermill": { - "duration": 0.003146, - "end_time": "2026-09-16T13:57:28.387929", - "exception": false, - "start_time": "2026-09-16T13:57:28.384783", - "status": "completed" - }, - "tags": [] - }, - "source": [ - "### Lire l'injection native : l'outil de transfert que nous n'avons pas écrit\n", - "\n", - "Trois lignes : `Racine de l'arbre : coder`, `Sous-agents declares : ['verificateur']`, puis la phrase clé — `L'outil natif transfer_to_agent est injecte par ADK des que la hierarchie existe`. La lecture importante est dans « injecté » : la cellule n'a écrit **aucun** code de transfert. Déclarer un sous-agent dans l'arbre suffit à ce que le runtime ADK ajoute l'outil `transfer_to_agent` à l'ensemble d'outils du parent — le handoff du §3 sera déclenché par un appel d'outil dont l'existence même est un fait de la déclaration, pas de la programmation. C'est la différence entre câbler un mécanisme et le laisser émerger de la structure." - ] - }, { "cell_type": "markdown", "id": "98d9afea", @@ -319,25 +281,6 @@ "print(f\"Agent final : {resultat.final_agent}\")\n" ] }, - { - "cell_type": "markdown", - "id": "d306970b", - "metadata": { - "papermill": { - "duration": 0.001509, - "end_time": "2026-09-16T13:57:31.516068", - "exception": false, - "start_time": "2026-09-16T13:57:31.514559", - "status": "completed" - }, - "tags": [] - }, - "source": [ - "### Lire ce que le runtime imprime avant la réponse : le coût caché du handoff\n", - "\n", - "Avant les compteurs du tour, la sortie porte un avertissement du runtime qui mérite sa propre lecture : `can transfer between agents but has no context_cache_config. Every transfer swaps the system instruction and the tool set, so the request prefix changes and the whole prompt is re-sent uncached after each transfer`. Traduit : **chaque handoff change l'instruction système et l'ensemble d'outils** de l'agent courant — le préfixe de requête change, et l'intégralité du prompt est re-soumise sans cache. Le handoff C5 est souple (décidé pendant le tour) mais **paie ce transport** : c'est le coût structurel que la désignation C4 du Lab 12b n'a pas (chaque étape est une conversation dont le périmètre est posé d'avance). Le second avertissement (JSON_SCHEMA EXPÉRIMENTAL, avec le filtre de la cellule de configuration) est bénin ; il témoigne simplement que l'outil de transfert passe par la même machinerie de déclaration que les autres outils." - ] - }, { "cell_type": "markdown", "id": "3ae24fe5", @@ -449,25 +392,6 @@ " \"etait apparue DANS un seul tour, decidee par le LLM.\")\n" ] }, - { - "cell_type": "markdown", - "id": "341f4684", - "metadata": { - "papermill": { - "duration": 0.002089, - "end_time": "2026-09-16T13:57:34.380099", - "exception": false, - "start_time": "2026-09-16T13:57:34.378010", - "status": "completed" - }, - "tags": [] - }, - "source": [ - "### Lire la séquence côté appelant : deux conversations mono-main\n", - "\n", - "La sortie aligne les deux étapes : `etape 1 (code, decidee par l'appelant) -> mains : ('coder',)` puis `etape 2 (verif, decidee par l'appelant) -> mains : ('verificateur_autonome',)`. Deux observations. **Un agent par conversation** : ici coder et `verificateur_autonome` sont deux agents SÉPARÉS (pas un arbre racine/sous-agent) — la séquence vit dans la liste Python de l'appelant, chaque tour reste mono-main. **Le contraste avec le §3** : la même intention (« écris puis fais vérifier ») s'y était réalisée dans UN tour, la main passant à l'intérieur — ici elle passe entre deux tours, par décision du code appelant. Le commentaire final imprimé le pose : C4 met la séquence dans nos données, C5 la laisse apparaître dans le tour." - ] - }, { "cell_type": "markdown", "id": "05373620", @@ -750,27 +674,6 @@ "print(\"Exercice a completer\")\n" ] }, - { - "cell_type": "markdown", - "id": "c60ff957", - "metadata": { - "papermill": { - "duration": 0.002504, - "end_time": "2026-09-16T13:57:39.033943", - "exception": false, - "start_time": "2026-09-16T13:57:39.031439", - "status": "completed" - }, - "tags": [] - }, - "source": [ - "### Lire les trois exercices : détecter, étendre, isoler\n", - "\n", - "Les trois cellules d'exercice sont des stubs C.1 suivant le patron canonique (invite « Exercice à compléter » imprimée par chaque stub) — contrat d'exécution bout-en-bout, validation par l'étudiant. L'échelle des énoncés : **Exercice 1** construit un détecteur de handoff manquant — un agent qui devait transférer vers le vérificateur et répond lui-même : comment l'observer depuis les compteurs `handoffs`/`mains` ? (le §3 a montré la main passée ; l'exercice demande de reconnaître l'absence) ; **Exercice 2** étend l'arbre à trois agents — le transfert devient-il une chaîne, et que devient l'ensemble d'outils de chaque niveau ? ; **Exercice 3** vérifie l'isolement des hiérarchies — deux conversations racines distinctes doivent garder leurs mains séparées, même quand les sous-agents portent le même nom. Trois niveaux : instrumenter l'absence, croître la structure, borner la portée.\n", - "\n", - "Comme dans le Lab 12b, noter la forme : chaque stub imprime l'invite canonique « Exercice à compléter » — l'output atteste l'exécution, la solution reste celle de l'étudiant. Le reste du notebook a établi ses observables un à un — l'arbre déclaré, l'outil injecté, le coût d'avertissement du transfert, les mains tour par tour — et l'exercice prend le relais exactement là où l'observable devient celui de l'étudiant. La conclusion ci-dessous referme le contrat C5 : le handoff est le seul des deux mécanismes où le **modèle** choisit le prochain locuteur pendant le tour — avec le coût de transport que le runtime a imprimé au §3, et la persistance de la main que le §5 a mesurée sur trois tours." - ] - }, { "cell_type": "markdown", "id": "e8383d45", From cacc5dbecafaf2ac32bc8c76ae9fc88dba5ff56a Mon Sep 17 00:00:00 2001 From: Claude Sonnet 5 Date: Mon, 21 Sep 2026 01:31:44 +0200 Subject: [PATCH 13/15] fix(#17040): retablir la section Objectif(s) perdue dans 2.11b-Proximal-Operators-From-Scratch Restauration verbatim de la lecture de la figure de convergence (cellule base c131i7figure) a sa position structurelle d'origine, entre le code de comparaison ISTA/FISTA sur l'objectif et la synthese : la campagne avait supprime 8 cellules Lecture dont 3 portaient le mot objectif (usage mathematique, fonction objectif) ; cette lecture est le porteur le plus central du motif et la tete laissait 4 cellules code consecutives sans interpretation. Co-Authored-By: Claude Sonnet 5 --- ....11b-Proximal-Operators-From-Scratch.ipynb | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/MyIA.AI.Notebooks/ML/DataScienceWithAgents/02-ML-Cours/2.11b-Proximal-Operators-From-Scratch.ipynb b/MyIA.AI.Notebooks/ML/DataScienceWithAgents/02-ML-Cours/2.11b-Proximal-Operators-From-Scratch.ipynb index 80167b7e0c..0e8622f5ec 100644 --- a/MyIA.AI.Notebooks/ML/DataScienceWithAgents/02-ML-Cours/2.11b-Proximal-Operators-From-Scratch.ipynb +++ b/MyIA.AI.Notebooks/ML/DataScienceWithAgents/02-ML-Cours/2.11b-Proximal-Operators-From-Scratch.ipynb @@ -596,6 +596,37 @@ "plt.show()" ] }, + { + "cell_type": "markdown", + "id": "c131i7figure", + "metadata": {}, + "source": [ + "### Ce que la figure montre, et le raccourci qu'elle prend\n", + "\n", + "Le panneau gauche trace l'objectif `f(x^k)` en echelle lineaire, le panneau\n", + "droit le meme ecart en log-log. Deux points de methode avant d'y lire une\n", + "acceleration.\n", + "\n", + "- **L'axe vertical du panneau droit n'est pas l'ecart a l'optimum exact.** Le\n", + " code trace `hist - hist[-1] + 1e-12` : la derniere valeur atteinte sert de\n", + " substitut a `f(x*)`, qui n'est pas connu analytiquement ici. Le procede est\n", + " legitime — les deux methodes rendent le meme point, donc leur `hist[-1]`\n", + " coincide a la precision affichee — mais la pente lue a droite de la figure\n", + " est celle de l'ecart a *cette* reference, pas a l'optimum du probleme. Le\n", + " plancher `1e-12` evite le logarithme de zero.\n", + "- **La figure ne remplace pas un compteur d'iterations.** Les deux courbes\n", + " partagent le meme axe `k`, mais aucun des deux runs n'imprime son nombre\n", + " d'iterations effectives ; la comparaison des pentes reste donc un argument\n", + " qualitatif, coherent avec la theorie `O(1/k)` contre `O(1/k^2)`\n", + " (Beck & Teboulle 2009), et non une verification chiffree.\n", + "\n", + "C'est le partage que ce notebook permet de faire, et il vaut la peine d'etre\n", + "dit : l'accord **quantitatif** des quatre solveurs est imprime (erreurs,\n", + "supports, temps), tandis que l'**acceleration** de FISTA reste visible sur la\n", + "figure sans etre chiffree. Une lecture honnete ne transfere pas la solidite de\n", + "l'un vers l'autre.\n" + ] + }, { "cell_type": "markdown", "id": "8db42684", From f3c42b5408867c27d4f71ed2d832ab39bc59d47b Mon Sep 17 00:00:00 2001 From: Claude Sonnet 5 Date: Mon, 21 Sep 2026 02:08:21 +0200 Subject: [PATCH 14/15] fix(#17040): retablir 7 sections de plan perdues (2.11b, 2.3b, 2.3d, 2.4) Restaurations verbatim (zero absorption, verifiees par lecture head) : - 2.11b : Carte d'identite de l'experience (regime, budget de mesures, bruit non orthogonal, erreur absolue) entre le code de generation et le choix de lambda. - 2.3b : guides des exercices 1 et 2 (log-probabilites/sous-flottage, lissage Laplace, contre-epreuve ; amplificateur de dimension et plafond d'independance) apres chaque stub. - 2.3d : La question de ce notebook (these + feuille de route) en tete. - 2.4 : Lecture du podium (regne des worst + deux precautions) et Lecture 0,947 (residus vs vote, precaution du split unique). Re-ancrage consolide : - 2.3d : Le protocole avant les resultats -- les trois regimes restent decrits par la section 3 ; seul le dispositif de lecture a priori (20 graines, ecart-type, moins d'un sigma = bruit) est reintroduit. Co-Authored-By: Claude Sonnet 5 --- ....11b-Proximal-Operators-From-Scratch.ipynb | 46 +++++++++++++++++++ .../2.3b-Naive-Bayes-Generatif.ipynb | 20 ++++++++ .../2.3d-Modele-Gaussien-LDA-QDA.ipynb | 25 ++++++++++ .../2.4-Arbres-Forets-Ensembles.ipynb | 24 ++++++++++ 4 files changed, 115 insertions(+) diff --git a/MyIA.AI.Notebooks/ML/DataScienceWithAgents/02-ML-Cours/2.11b-Proximal-Operators-From-Scratch.ipynb b/MyIA.AI.Notebooks/ML/DataScienceWithAgents/02-ML-Cours/2.11b-Proximal-Operators-From-Scratch.ipynb index 0e8622f5ec..9ea3cefbb6 100644 --- a/MyIA.AI.Notebooks/ML/DataScienceWithAgents/02-ML-Cours/2.11b-Proximal-Operators-From-Scratch.ipynb +++ b/MyIA.AI.Notebooks/ML/DataScienceWithAgents/02-ML-Cours/2.11b-Proximal-Operators-From-Scratch.ipynb @@ -388,6 +388,52 @@ "print(f'||bruit||_2 / ||b_clean||_2 = {np.linalg.norm(noise)/np.linalg.norm(b_clean):.4f}')" ] }, + { + "cell_type": "markdown", + "id": "c131i2regime", + "metadata": {}, + "source": [ + "### Carte d'identite de l'experience, et ce que le tirage dit deja\n", + "\n", + "Les quatre lignes de sortie fixent le regime complet. Le tableau les reprend,\n", + "avec les quantites derivees qui serviront a lire tous les resultats suivants :\n", + "\n", + "| Quantite | Valeur | Lecture |\n", + "|---|---:|---|\n", + "| Dimension du signal `p` | 500 | inconnues |\n", + "| Mesures `n` | 200 | equations |\n", + "| Ratio `n/p` | 0.40 | systeme 2.5x sous-determine |\n", + "| Support vrai `k` | 30 | densite 6.00 % |\n", + "| Bruit relatif `||e||_2 / ||A x*||_2` | 0.0204 | 2.04 % du signal |\n", + "| Graine `rng` | 42 | tirage reproductible |\n", + "\n", + "**La condition de comptage est confortable.** L'heuristique usuelle du\n", + "compressed sensing demande un nombre de mesures de l'ordre de `k log(p/k)` ;\n", + "ici `30 x log(500/30) = 30 x 2.81 = 84.4`, soit un budget de mesures 2.4 fois\n", + "superieur au seuil. On doit donc s'attendre a une recuperation de support tres\n", + "bonne (mesuree a `R = 0.933` plus bas) : l'experience teste un regime\n", + "*confortable*, pas la frontiere theorique ou la recuperation s'effondre.\n", + "\n", + "**Le bruit tire n'est pas orthogonal au signal.** La sortie donne\n", + "`||b||_2 = 7.0591` et `||A x*||_2 = 7.0345`, soit un allongement de `0.0246`.\n", + "Or `||e||_2 = 0.0204 x 7.0345 = 0.1435`, et si `e` etait orthogonal a `A x*`\n", + "l'allongement attendu serait `||e||^2 / (2 ||A x*||) = 0.0206 / 14.07 =\n", + "0.0015`. L'allongement observe est **17 fois** cette prediction : il ne peut\n", + "donc pas venir du terme quadratique, il vient du produit scalaire\n", + "`2 = 0.3467 - 0.0206 = 0.3261` (en normes carrees), soit\n", + "`cos(A x*, e) ~ 0.16`. Pour `n = 200` coordonnees, un bruit independant\n", + "produit typiquement un alignement de `1/sqrt(n) = 0.07` : l'ecart observe\n", + "reste du meme ordre de grandeur. La lecon de lecture est nette : **un ecart de\n", + "normes entre `b` et `A x*` ne mesure pas la taille du bruit**, et ne doit pas\n", + "etre presente comme tel.\n", + "\n", + "**L'erreur des cellules suivantes est absolue.** Le script calcule\n", + "`err_L2 = ||x - x*||_2` (norme euclidienne, sans normalisation), et\n", + "`||x*||_2` n'est imprime nulle part : les `0.1316` qui reviennent dans tout le\n", + "notebook se lisent donc en valeur absolue, pas en pourcentage. Ce detail de\n", + "definition evite le contresens le plus courant sur ce genre de tableau.\n" + ] + }, { "cell_type": "code", "execution_count": 6, diff --git a/MyIA.AI.Notebooks/ML/DataScienceWithAgents/02-ML-Cours/2.3b-Naive-Bayes-Generatif.ipynb b/MyIA.AI.Notebooks/ML/DataScienceWithAgents/02-ML-Cours/2.3b-Naive-Bayes-Generatif.ipynb index a1f3b4948f..d3b33bc9af 100644 --- a/MyIA.AI.Notebooks/ML/DataScienceWithAgents/02-ML-Cours/2.3b-Naive-Bayes-Generatif.ipynb +++ b/MyIA.AI.Notebooks/ML/DataScienceWithAgents/02-ML-Cours/2.3b-Naive-Bayes-Generatif.ipynb @@ -544,6 +544,16 @@ "print(\"Exercice 1 a completer : Multinomial NB de zero (voir code ci-dessus)\")" ] }, + { + "cell_type": "markdown", + "id": "8a3042c9", + "metadata": {}, + "source": [ + "### Ce que votre complétion doit produire — le guide de l'exercice 1\n", + "\n", + "Le Multinomial NB remplace les densités gaussiennes par des **comptages** : une distribution de probabilité sur les occurrences (mots, tokens, catégories) plutôt qu'un ajustement en cloche. Trois pièges classiques guident la complétion. D'abord, calculez les log-probabilités et sommez — le produit de milliers de probabilités inférieures à 1 sous-flotte en `float64` bien avant la fin du vocabulaire ; l'espace log est la pratique universelle, pas un raffinement. Ensuite, le **lissage de Laplace** (`+1` aux comptes, normalisation au vocabulaire `+V`) : sans lui, un mot absent du train attribue une probabilité nulle à toute la classe, où qu'il apparaisse — une seule observation invisible tuerait le verdict. Enfin, la contre-épreuve attendue : vos probabilités a posteriori doivent reproduire les prédictions de `sklearn.naive_bayes.MultinomialNB` exactement, comme la cellule 1.2 l'a fait pour le cas gaussien — la vérification vaut preuve, toujours." + ] + }, { "cell_type": "markdown", "id": "b81c29ba", @@ -601,6 +611,16 @@ "print(\"Exercice 2 a completer : ecart NB-LR a n=30 par dimension =\", ecart_d)" ] }, + { + "cell_type": "markdown", + "id": "b06092b7", + "metadata": {}, + "source": [ + "### Ce que vous devriez observer — le guide de l'exercice 2\n", + "\n", + "La théorie prédit un **amplificateur** : l'avantage génératif au petit `n` grandit avec la dimension. Comptez les paramètres — NB estime `2d` quantités (une moyenne, une variance par caractéristique), chacune depuis `n` observations ; la régression logistique estime `d` poids *conjointement*, chaque poids ne se stabilisant qu'avec assez d'observations couvrant les covariations. À `n = 30` fixé, monter `d` retire des degrés de liberté au discriminatif bien plus vite qu'au génératif : l'écart `NB − LR` devrait s'élargir avec `d` — avant de plafonner, car l'hypothèse d'indépendance impose à NB son propre plafond (le scénario B ci-dessus en est la démonstration : une fois la corrélation en bloc installée, plus de dimension n'aide plus NB, elle l'enfonce). Votre valeur `None` mesurée complètera la colonne manquante de cette histoire." + ] + }, { "cell_type": "markdown", "id": "d0280cc0", diff --git a/MyIA.AI.Notebooks/ML/DataScienceWithAgents/02-ML-Cours/2.3d-Modele-Gaussien-LDA-QDA.ipynb b/MyIA.AI.Notebooks/ML/DataScienceWithAgents/02-ML-Cours/2.3d-Modele-Gaussien-LDA-QDA.ipynb index 46cebf7f3d..8921e031fe 100644 --- a/MyIA.AI.Notebooks/ML/DataScienceWithAgents/02-ML-Cours/2.3d-Modele-Gaussien-LDA-QDA.ipynb +++ b/MyIA.AI.Notebooks/ML/DataScienceWithAgents/02-ML-Cours/2.3d-Modele-Gaussien-LDA-QDA.ipynb @@ -65,6 +65,16 @@ "plt.rcParams[\"figure.figsize\"] = (6, 4)\n" ] }, + { + "cell_type": "markdown", + "id": "lect23d-01", + "metadata": {}, + "source": [ + "### La question de ce notebook\n", + "\n", + "Quatre classifieurs — LDA, QDA, régression logistique, Naive Bayes — vont être confrontés aux **mêmes données**, et la seule chose qui variera est **l'hypothèse de covariance** des classes : partagée, propres, ou diagonale. La thèse à éprouver : le meilleur modèle n'est pas le plus flexible, mais **celui dont l'hypothèse colle à la réalité des données**. Chaque section apporte une pièce : le calcul exact de la frontière (§1-2), des régimes contrôlés où l'on sait quelle hypothèse est vraie (§3), la géométrie des frontières (§4), la qualité des probabilités (§5), et la limite en grande dimension (§6)." + ] + }, { "cell_type": "markdown", "id": "d302bff5", @@ -253,6 +263,21 @@ "On compare sur les **mêmes splits et graines** [2.3](2.3-Regression-lineaire-logistique.ipynb) : LDA, QDA, logistique (linéaire), Naive Bayes (gaussien diagonal).\n" ] }, + { + "cell_type": "markdown", + "id": "prot1c9e2", + "metadata": {}, + "source": [ + "### Le protocole avant les résultats\n", + "\n", + "Un seul facteur est manipulé — la structure de covariance, décrite par\n", + "les trois régimes ci-dessus. Chaque accuracy est moyennée sur **20 graines**\n", + "avec son écart-type : une différence de moins d'un écart-type ne se lit pas\n", + "comme un signal, mais comme du bruit de split. C'est ce dispositif — facteur\n", + "contrôlé, répétition, barre d'erreur — qui autorisera la lecture d'après à\n", + "parler de *signature de l'hypothèse* et non de loterie d'un split chanceux." + ] + }, { "cell_type": "code", "execution_count": 4, diff --git a/MyIA.AI.Notebooks/ML/DataScienceWithAgents/02-ML-Cours/2.4-Arbres-Forets-Ensembles.ipynb b/MyIA.AI.Notebooks/ML/DataScienceWithAgents/02-ML-Cours/2.4-Arbres-Forets-Ensembles.ipynb index e33d2ad2f0..58db818766 100644 --- a/MyIA.AI.Notebooks/ML/DataScienceWithAgents/02-ML-Cours/2.4-Arbres-Forets-Ensembles.ipynb +++ b/MyIA.AI.Notebooks/ML/DataScienceWithAgents/02-ML-Cours/2.4-Arbres-Forets-Ensembles.ipynb @@ -634,6 +634,18 @@ "plt.show()" ] }, + { + "cell_type": "markdown", + "id": "dc1fd5f7", + "metadata": {}, + "source": [ + "### Lecture du podium : le règne des « worst » — et ses limites\n", + "\n", + "Les quatre variables en tête — *worst concave points* (0,159), *worst area* (0,147), *worst perimeter* (0,086), *worst radius* (0,079) — sont toutes des statistiques « worst » : la valeur **la plus extrême** mesurée sur la cellule, pas sa moyenne. Cliniquement parlant : un noyau globalement calme mais présentant *une* zone très concave est plus suspects qu'un noyau uniformément médiocre — l'information diagnostique vit dans les extrêmes. C'est un résultat interprétable, obtenu sans hypothèse médicale préalable.\n", + "\n", + "Deux précautions avant de sur-interpréter. Les importances par **diminution d'impureté** sont calculées sur le train : elles récompensent les variables qui *séparent le jeu d'entraînement*, pas nécessairement celles qui généralisent. Et des variables corrélées (périmètre, rayon et aire d'une même cellule sont géométriquement liés) se *partagent* le crédit : chaque coupure revient à celle que l'arbre a rencontrée en premier, les sœurs repartent avec presque rien — la vraie importance du trio « taille » est diluée dans trois podiums distincts. L'exercice 2 vous fait vérifier la lecture du podium ; la permutation d'importances (non traitée ici) lève la seconde réserve." + ] + }, { "cell_type": "markdown", "id": "2a4c0011", @@ -761,6 +773,18 @@ "print(f\"Boosting -- accuracy test : {acc_test_boosting:.3f}\")" ] }, + { + "cell_type": "markdown", + "id": "5cd3bade", + "metadata": {}, + "source": [ + "### Lecture : 0,947 — corriger les résidus plutôt que voter\n", + "\n", + "Sur cette découpe, l'échelle est nette : arbre seul **0,918** < forêt **0,936** < boosting **0,947**. Le mécanisme diffère radicalement du vote : le boosting construit les arbres **séquentiellement**, chaque arbre nouveau apprenant les *résidus* (les erreurs) du modèle courant — l'ensemble est une somme additive où chaque maillon corrige le précédent, là où la forêt fait tirer ses sommets en parallèle et moyenne. Résultat : là où la forêt réduit la **variance** sans toucher au biais, le boosting réduit le **biais** (et peut le sur-corriger : c'est le modèle des trois qui surapprend le plus vite quand on pousse le nombre d'estimateurs).\n", + "\n", + "La précaution d'usage : ces trois nombres viennent d'un **seul** découpage train/test (171 exemples de test) — un point d'accuracy y pèse 0,6 %, l'écart forêt/boosting (1,1 point) tient dans deux exemples. L'exercice 3 vous demande précisément cette comparaison propre ; la validation croisée du notebook **2.5** dira si l'échelle tient en moyenne." + ] + }, { "cell_type": "markdown", "id": "2a4c0015", From e2b7b7e1ad071996b44094a489f8015d091c1c57 Mon Sep 17 00:00:00 2001 From: Claude Sonnet 5 Date: Mon, 21 Sep 2026 02:36:06 +0200 Subject: [PATCH 15/15] fix(#17066): retitrer distinctement les 'Lecture du resultat' x4 (Lab12b, Lab12c) Chaque occurrence lit un observable DISTINCT du lab. Lab12b : le plan imprime avant execution, la conformite a la designation, les agents declares mais non designes, memoire commune vs isolation entre chaines. Lab12c : l'arbre d'agents declare, le transfert decide par le LLM en plein tour, la sequence de deux tours mono-agent, la duree du handoff au-dela du tour. Retitrage distinct (doctrine #17066 : experiences legitimes distinctes), aucune consolidation -- zero redondance verifiee par lecture exhaustive des 8 occurrences. Markdown uniquement, seule la ligne de titre change ; corps et cellules code byte-identiques. Co-Authored-By: Claude Sonnet 5 --- .../Day5-DS-Star/Lab12b-Sequential-Orchestration.ipynb | 8 ++++---- .../Day5-DS-Star/Lab12c-Agent-Handoff.ipynb | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/MyIA.AI.Notebooks/ML/DataScienceWithAgents/Track2-GoogleADK/Day5-DS-Star/Lab12b-Sequential-Orchestration.ipynb b/MyIA.AI.Notebooks/ML/DataScienceWithAgents/Track2-GoogleADK/Day5-DS-Star/Lab12b-Sequential-Orchestration.ipynb index 6888f894ca..b6d982b8da 100644 --- a/MyIA.AI.Notebooks/ML/DataScienceWithAgents/Track2-GoogleADK/Day5-DS-Star/Lab12b-Sequential-Orchestration.ipynb +++ b/MyIA.AI.Notebooks/ML/DataScienceWithAgents/Track2-GoogleADK/Day5-DS-Star/Lab12b-Sequential-Orchestration.ipynb @@ -217,7 +217,7 @@ "tags": [] }, "source": [ - "### Lecture du résultat\n", + "### Lecture du résultat — le plan avant l'exécution\n", "\n", "Le plan est imprimé **avant** l'exécution : c'est l'observable de la stratégie. Les quatre agents sont de vrais `Agent` ADK — l'orchestrateur n'assemble que des primitives publiques (un `Runner` par étape, un `InMemorySessionService` partagé), jamais une restauration du moteur SK (#14058)." ] @@ -309,7 +309,7 @@ "tags": [] }, "source": [ - "### Lecture du résultat\n", + "### Lecture du résultat — la chaîne a suivi la désignation\n", "\n", "`agent_hands` rend la chaîne (`planner`, `coder`, `executor`, `verifier`) : l'exécution a suivi la désignation déclarée. L'exécuteur a invoqué `dataset_profile` — ses chiffres dans la réponse finale viennent de l'outil, pas d'une invention du modèle. La réponse finale est celle du **dernier désigné** (`final_agent`)." ] @@ -402,7 +402,7 @@ "tags": [] }, "source": [ - "### Lecture du résultat\n", + "### Lecture du résultat — coder et executor non désignés\n", "\n", "Deux mains seulement (`planner`, `verifier`), aucun appel d'outil : coder et executor existent toujours, ils ne sont simplement **pas désignés**. Changer l'ordre d'une chaîne C4 = changer une ligne de données ; changer le cours d'un handoff C5 = réécrire l'instruction d'un agent. Les deux contrats cohabitent sans se recouvrir." ] @@ -506,7 +506,7 @@ "tags": [] }, "source": [ - "### Lecture du résultat\n", + "### Lecture du résultat — mémoire commune, isolation entre chaînes\n", "\n", "Côté mémoire : l'historique de la chaîne A liste bien ses auteurs dans l'ordre désigné — chacun a lu ses prédécesseurs. Côté isolation : `fuite = False` — la chaîne B n'a rien vu de la conversation de A. La mémoire est commune *à l'intérieur* d'une chaîne, jamais *entre* chaînes : c'est le contrat C1 qui reste tenu, désignation ou pas." ] diff --git a/MyIA.AI.Notebooks/ML/DataScienceWithAgents/Track2-GoogleADK/Day5-DS-Star/Lab12c-Agent-Handoff.ipynb b/MyIA.AI.Notebooks/ML/DataScienceWithAgents/Track2-GoogleADK/Day5-DS-Star/Lab12c-Agent-Handoff.ipynb index b80a2f4797..bcfdf19b1b 100644 --- a/MyIA.AI.Notebooks/ML/DataScienceWithAgents/Track2-GoogleADK/Day5-DS-Star/Lab12c-Agent-Handoff.ipynb +++ b/MyIA.AI.Notebooks/ML/DataScienceWithAgents/Track2-GoogleADK/Day5-DS-Star/Lab12c-Agent-Handoff.ipynb @@ -190,7 +190,7 @@ "tags": [] }, "source": [ - "### Lecture du résultat\n", + "### Lecture du résultat — l'arbre d'agents déclaré\n", "\n", "La racine `coder` déclare exactement un sous-agent, `verificateur`. L'arbre est de vrais `Agent` ADK — jamais une restauration du moteur SK (#14058) : la décision actée reste ADK comme runtime." ] @@ -295,7 +295,7 @@ "tags": [] }, "source": [ - "### Lecture du résultat\n", + "### Lecture du résultat — le LLM a décidé du transfert\n", "\n", "Le couple clé : `tool_calls` contient `transfer_to_agent`, et `agent_hands` montre la main passant de `coder` à `verificateur`. C'est le **LLM** qui a décidé du transfert, au milieu du tour — le handoff n'est ni ordonnancé ni simulé par l'appelant. La réponse finale vient du vérificateur (`final_agent`)." ] @@ -406,7 +406,7 @@ "tags": [] }, "source": [ - "### Lecture du résultat\n", + "### Lecture du résultat — deux tours mono-agent enchaînés\n", "\n", "Deux conversations mono-agent enchaînées par l'appelant : chaque tour reste mono-main, la séquence existe seulement dans la liste `traces` de notre code. Au §3, la même intention (« écris puis fais vérifier ») s'était réalisée **dans un seul tour**, par décision du modèle — c'est toute la différence entre les deux contrats." ] @@ -493,7 +493,7 @@ "tags": [] }, "source": [ - "### Lecture du résultat\n", + "### Lecture du résultat — un transfert durable du point d'entrée\n", "\n", "Le tour 1 reste mono-main (`coder`), le tour 2 porte le handoff observable (`(('coder', 'verificateur'),)` dans `handoffs`). Le tour 3 révèle un comportement précieux : la conversation ne repart **pas** de la racine — la main est restée au vérificateur (`mains = ('verificateur',)`, aucun handoff). ADK mémorise l'agent courant au-delà du tour : le handoff est un transfert **durable** du point d'entrée, pas un écart d'un seul tour. L'historique persiste (contrat C1b) : le résumé du tour 3 s'appuie sur tout ce qui précède." ]