From 5d365a4b50fd6eb7cd584ef43704de9b9e7862c5 Mon Sep 17 00:00:00 2001 From: jsboige Date: Wed, 9 Sep 2026 19:34:48 +0200 Subject: [PATCH 1/2] =?UTF-8?q?feat(notebooks,#11601):=20DecPyMC-12=20dens?= =?UTF-8?q?it=C3=A9=201214->1606=20=E2=80=94=20lectures=20ancr=C3=A9es=20s?= =?UTF-8?q?ur=20les=20sorties=20(markdown-only)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 8 extensions de cellules md existantes, aucune cellule ajoutée (plan-loss vert à l'arrivée). Prose 17005->22494 sur 14 cellules code = densité 1606 (>=1500, ronde 2). Voir #11601 — 2e PR umbrella du jour (cap 2). Co-Authored-By: Claude-Code --- .../DecPyMC-12-Freq-Sev-Hierarchique.ipynb | 28 +++++++++++++++---- 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/MyIA.AI.Notebooks/Probas/DecisionTheory/PyMC/DecPyMC-12-Freq-Sev-Hierarchique.ipynb b/MyIA.AI.Notebooks/Probas/DecisionTheory/PyMC/DecPyMC-12-Freq-Sev-Hierarchique.ipynb index 7b110fe1eb..e0194fd1b9 100644 --- a/MyIA.AI.Notebooks/Probas/DecisionTheory/PyMC/DecPyMC-12-Freq-Sev-Hierarchique.ipynb +++ b/MyIA.AI.Notebooks/Probas/DecisionTheory/PyMC/DecPyMC-12-Freq-Sev-Hierarchique.ipynb @@ -148,7 +148,9 @@ "\n", "$$\\pi_k = \\lambda_k \\times \\mathbb{E}[S_k] = \\lambda_k \\, \\exp\\big(\\mu_k + \\tfrac{\\sigma^2}{2}\\big)$$\n", "\n", - "La difficulté n'est pas la formule, c'est **qui** a assez de données pour l'estimer. On observe chaque segment sur `T = 3` ans, avec des tailles de portefeuille **volontairement inégales** — de 15 à 300 polices. Un segment de 20 polices (60 p-années, ~7 sinistres) est un **bruit** ; un segment de 300 polices (900 p-années, ~110 sinistres) est une **mesure**. La tarification est exactement là : **comment estimer un risque quand on en a peu observé**." + "La difficulté n'est pas la formule, c'est **qui** a assez de données pour l'estimer. On observe chaque segment sur `T = 3` ans, avec des tailles de portefeuille **volontairement inégales** — de 15 à 300 polices. Un segment de 20 polices (60 p-années, ~7 sinistres) est un **bruit** ; un segment de 300 polices (900 p-années, ~110 sinistres) est une **mesure**. La tarification est exactement là : **comment estimer un risque quand on en a peu observé**.\n", + "\n", + "Cette inégalité d'information n'est pas un détail de laboratoire : elle structure le marché. Un segment sous-tarifé attire mécaniquement les mauvais risques (antisélection) ; un segment surtarifié se vide vers les concurrents. La tarification par segment exige donc un dosage : assez de collectif pour stabiliser les petits segments, assez d'individualité pour ne pas effacer les gros. Toute la suite est l'exploration quantitative de ce dosage — deux extrêmes qui échouent chacun à leur manière (section 3), et un modèle hiérarchique qui calibre le curseur sur les données (sections 4 à 8)." ] }, { @@ -291,7 +293,9 @@ "\n", "**Partial pooling (hiérarchique)** — on estime la distribution collective **et** le déplacement de chaque segment, en laissant les données de tous les segments renforcer celles de chacun. C'est le modèle bayésien de la section suivante.\n", "\n", - "Calculons d'abord les deux stratégies naïves pour avoir le contraste." + "Calculons d'abord les deux stratégies naïves pour avoir le contraste.\n", + "\n", + "L'ordre de grandeur se calcule à la main : pour un comptage Poissonnien d'exposition $n_k T$, l'erreur relative de $\\hat\\lambda_k^{no}$ vaut $1/\\sqrt{N_k}$. Le plus petit segment (B15 : 15 polices, 9 sinistres) porte donc ±33 % d'erreur sur la seule fréquence — avant d'ajouter la variance de $\\hat\\mu_k^{no}$, du même ordre pour 9 sinistres lognormaux. À l'autre extrémité, B8 (250 polices, 106 sinistres) tombe sous 10 %. C'est exactement cette décroissance en $1/\\sqrt{N_k}$ que le gradient de shrinkage de la section 8 convertira en poids de collectif : le modèle bayésien apprend ce calcul d'incertitude sans qu'on le lui écrive." ] }, { @@ -491,7 +495,9 @@ "source": [ "## 5. Échantillonnage NUTS\n", "\n", - "On tire 2 chaînes de 1 500 draws (1 500 de warmup). Le modèle est compact : ~50 dimensions latentes (20 segments × 2 hiérarchies), l'inférence est rapide." + "On tire 2 chaînes de 1 500 draws (1 500 de warmup). Le modèle est compact : ~50 dimensions latentes (20 segments × 2 hiérarchies), l'inférence est rapide.\n", + "\n", + "Le `target_accept=0.90` — plus haut que le 0.80 par défaut — demande à NUTS des pas plus fins : les échelles de hiérarchie ($\\tau_\\lambda$, $\\tau$, $\\sigma$) bornent les effets de segment, et leur géométrie en entonnoir est la partie raide de l'espace posterior, celle où des pas trop larges produiraient des divergences. Deux chaînes suffisent ici car la paramétrisation **non centrée** de la section précédente a aplani cet entonnoir ; les diagnostics de la section suivante le vérifient chiffres en main." ] }, { @@ -575,7 +581,9 @@ "source": [ "## 6. Diagnostics de convergence\n", "\n", - "On vérifie que NUTS a bien exploré : `r_hat` (proche de 1 = cohérence entre chaînes) et `ess_bulk` (taille effective d'échantillon, à comparer aux 3 000 draws théoriques). Un `r_hat` > 1.01 ou un `ess_bulk` faible sur un paramètre central signalerait un problème de paramétrisation." + "On vérifie que NUTS a bien exploré : `r_hat` (proche de 1 = cohérence entre chaînes) et `ess_bulk` (taille effective d'échantillon, à comparer aux 3 000 draws théoriques). Un `r_hat` > 1.01 ou un `ess_bulk` faible sur un paramètre central signalerait un problème de paramétrisation.\n", + "\n", + "Trois colonnes à surveiller dans le tableau : `r_hat` (attendu maximal sur les hyperparamètres de sévérité), `ess_bulk` (attendu minimal sur $\\sigma$), et la largeur des intervalles `eti89` — un paramètre à intervalle très large n'est pas mal échantillonné, il est **mal identifié** : les données ne portent quasiment pas d'information sur lui. Distinguer les deux verdicts change la réponse : un mauvais `r_hat` se soigne (reparamétrisation, plus de draws) ; une faible identification ne se soigne pas, elle se documente — et l'on vérifie alors que la quantité finale d'intérêt ($\\pi_k$) reste bien estimée malgré tout (section 7)." ] }, { @@ -638,6 +646,8 @@ "tags": [] }, "source": [ + "**Lecture du tableau ci-dessus.** Le bloc *fréquence* est propre : `log_lam0` (r_hat 1.00, ess_bulk 687) et `tau_lam` (1.01, 527) explorent sans difficulté. Le bloc *sévérité* est plus tendu : $\\mu$ monte à r_hat 1.03, et surtout $\\sigma$ — ess_bulk 44, ess_tail 32, intervalle [0.10, 0.95] autour d'une moyenne de 0.43 — est **mal identifié** plutôt que mal échantillonné : avec 7 à 106 sinistres par segment, $\\sum \\log S$ porte beaucoup d'information sur la moyenne mais très peu sur la dispersion. Le modèle apprend $\\sigma \\approx 0.43$ là où la vérité générationnelle est 0.70. Et c'est précisément pourquoi la prime reste utilisable : les erreurs sur $\\sigma$ et sur $\\mu$ se compensent en partie dans la combinaison $\\mu + \\sigma^2/2$ qui entre dans $\\pi_k$, et le RMSE global de cette section (0.2556, meilleur des trois stratégies) atteste que la quantité *utile* est bien estimée même quand un hyperparamètre ne l'est pas. Leçon générale du bayésien hiérarchique : diagnostiquer les paramètres un à un, mais juger sur la quantité de décision.\n", + "\n", "## 7. La prime pure postérieure (partial pooling)\n", "\n", "On résume $\\pi_k$ par sa **moyenne postérieure** — l'estimateur bayésien standard — et on la confronte à la vérité et aux deux stratégies naïves. Le partial pooling **resserre les petits segments vers le collectif** (là où no-pooling est bruité) tout en **laissant les gros parler** (là où full-pooling efface tout). Le tableau et le RMSE scindé par taille montrent le compromis : le partial pooling gagne **globalement** et **nettement sur les gros segments** ; sur les petits, il est **à quasi-égalité** — il lisse le bruit mais paie un biais sur les segments *réellement* extrêmes (à examiner à la section 8)." @@ -824,6 +834,8 @@ "tags": [] }, "source": [ + "**Lecture du tableau ci-dessus (gradient de shrinkage).** Les $s_k$ courent de 0.518 (B15, 15 polices) à 0.849 (B8, 250 polices), corrélés à 0.906 avec l'exposition : le lissage suit la taille, mécaniquement. Deux ordres de grandeur à retenir : aucun segment n'est écrasé — le plus petit garde plus de la moitié de son signal propre — et aucun n'est totalement libéré — le plus gros conserve environ 15 % de collectif. Le partial pooling de ce portefeuille est un compromis **continu**, pas un interrupteur gros/petits ; la section 11 montrera que la position de ce curseur, c'est $\\tau$ qui la fixe.\n", + "\n", "## 9. La décision de tarification : qui est mal-tarifé, et par quel schéma\n", "\n", "L'erreur n'est pas un chiffre abstrait : chaque écart de prime pure est une **décision**. Un segment *sous-tarifé* (prime estimée < prime vraie) est un **risque mal payé** — l'assureur collecte moins que le coût attendu. Un segment *surtarifé* est un risque chassé vers un concurrent, ou une prime injuste.\n", @@ -900,7 +912,9 @@ "source": [ "## 10. Visualiser le compromis\n", "\n", - "On trace la prime pure par segment pour les 4 estimations et la vérité, puis le gradient de shrinkage. Le verdict visuel : le no-pooling « saute » sur les petits segments, le full-pooling est une ligne plate qui nie l'hétérogénéité, le partial pooling suit la vérité **sans** l'excès de bruit des petits." + "On trace la prime pure par segment pour les 4 estimations et la vérité, puis le gradient de shrinkage. Le verdict visuel : le no-pooling « saute » sur les petits segments, le full-pooling est une ligne plate qui nie l'hétérogénéité, le partial pooling suit la vérité **sans** l'excès de bruit des petits.\n", + "\n", + "Deux signatures visuelles à reconnaître pour la suite : un modèle qui surajuste colle aux points mais vibre sur les petits segments (le no-pooling, cf. B17 estimé 874 € pour une vérité de 642 €) ; un modèle qui sous-ajuste est une ligne plate qui rate les extrêmes (le full-pooling, 527 € partout). Le partial pooling, lui, se trompe *lisiblement* : ses écarts à la vérité sont lisses, orientés par le collectif, pas par le bruit d'échantillonnage. Sur le panneau de droite, le nuage $s_k$ (exposition en échelle log) monte de ~0.52 à ~0.85 : la relation taille-shrinkage de la section 8, cette fois sous les yeux." ] }, { @@ -1171,6 +1185,8 @@ "tags": [] }, "source": [ + "**Lecture des sorties de la section 11.** Le modèle apprend $\\tau$ en dessous de sa vraie valeur (0.07 contre 0.05 au niveau faible — quasi exact ; 0.20 contre 0.25 ; 0.47 contre 0.60) : avec 20 segments, il sous-estime l'hétérogénéité réelle et lisse donc légèrement trop. La ligne RMSE est celle qui compte : no-pooling est **constant par construction** (0.379 — il n'utilise pas la hiérarchie), full-pooling explose de 0.41 à 3.38 quand $\\tau$ monte (×8), partial passe de 0.37 à 1.40 (×3.7) — et il bat les deux autres à **chaque** niveau. C'est la propriété de robustesse qui fait la valeur industrielle du hiérarchique : choisir no ou full, c'est parier sur une hypothèse d'hétérogénéité qu'on ne contrôle pas ; le partial pooling s'adapte au régime réel des données — imparfaitement (0.47 < 0.60), mais sans jamais être la pire option.\n", + "\n", "## 12. Le lien avec la crédibilité (T3) et la prime point (T1)\n", "\n", "**T3 (crédibilité Bühlmann–Straub)** dérive un poids *déterministe* $z_k = \\frac{n_k}{n_k + k}$ (où $k$ est le paramètre de crédibilité tiré des variances entre et dans les groupes) et estime $\\hat\\pi_k = z_k\\,\\text{(données)} + (1-z_k)\\,(\\text{moyenne collective})$.\n", @@ -1446,7 +1462,7 @@ "environment_variables": {}, "exception": null, "input_path": "DecPyMC-12-Freq-Sev-Hierarchique.ipynb", - "output_path": "C:/Users/jsboi/AppData/Local/Temp/claude/d--Dev-CoursIA/6d8653b3-f41e-4ede-baaa-f7100472ccbf/scratchpad/dec12_out.ipynb", + "output_path": "DecPyMC-12-Freq-Sev-Hierarchique.ipynb", "parameters": {}, "start_time": "2026-08-25T09:44:59.495041", "version": "2.6.0" From 1526d70b82e3a46a890f19609361b349a0e10568 Mon Sep 17 00:00:00 2001 From: jsboige Date: Wed, 9 Sep 2026 23:58:22 +0200 Subject: [PATCH 2/2] =?UTF-8?q?fix(notebooks,#11601):=20DecPyMC-12=20?= =?UTF-8?q?=E2=80=94=20diagnostics=20sigma=20reformules=20(review=2015412)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Les trois formulations flaggees par la review CHANGES_REQUESTED sont corrigees en markdown-only : deux defauts coexistants (identification faible ET echantillonnage insuffisant dans ce run), non-centre qui aide sans rendre les diagnostics propres, RMSE encourageant mais ne remplaçant pas un posterior converge. Aucun changement code/output. --- .../PyMC/DecPyMC-12-Freq-Sev-Hierarchique.ipynb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MyIA.AI.Notebooks/Probas/DecisionTheory/PyMC/DecPyMC-12-Freq-Sev-Hierarchique.ipynb b/MyIA.AI.Notebooks/Probas/DecisionTheory/PyMC/DecPyMC-12-Freq-Sev-Hierarchique.ipynb index e0194fd1b9..cd35fbc61e 100644 --- a/MyIA.AI.Notebooks/Probas/DecisionTheory/PyMC/DecPyMC-12-Freq-Sev-Hierarchique.ipynb +++ b/MyIA.AI.Notebooks/Probas/DecisionTheory/PyMC/DecPyMC-12-Freq-Sev-Hierarchique.ipynb @@ -497,7 +497,7 @@ "\n", "On tire 2 chaînes de 1 500 draws (1 500 de warmup). Le modèle est compact : ~50 dimensions latentes (20 segments × 2 hiérarchies), l'inférence est rapide.\n", "\n", - "Le `target_accept=0.90` — plus haut que le 0.80 par défaut — demande à NUTS des pas plus fins : les échelles de hiérarchie ($\\tau_\\lambda$, $\\tau$, $\\sigma$) bornent les effets de segment, et leur géométrie en entonnoir est la partie raide de l'espace posterior, celle où des pas trop larges produiraient des divergences. Deux chaînes suffisent ici car la paramétrisation **non centrée** de la section précédente a aplani cet entonnoir ; les diagnostics de la section suivante le vérifient chiffres en main." + "Le `target_accept=0.90` — plus haut que le 0.80 par défaut — demande à NUTS des pas plus fins : les échelles de hiérarchie ($\\tau_\\lambda$, $\\tau$, $\\sigma$) bornent les effets de segment, et leur géométrie en entonnoir est la partie raide de l'espace posterior, celle où des pas trop larges produiraient des divergences. Deux chaînes sont tirées ici ; la paramétrisation **non centrée** de la section précédente aplatit cet entonnoir — elle aide la géométrie sans rendre les diagnostics propres : la section suivante montrera un $\\sigma$ à la fois faiblement identifié et insuffisamment échantillonné dans ce run." ] }, { @@ -646,7 +646,7 @@ "tags": [] }, "source": [ - "**Lecture du tableau ci-dessus.** Le bloc *fréquence* est propre : `log_lam0` (r_hat 1.00, ess_bulk 687) et `tau_lam` (1.01, 527) explorent sans difficulté. Le bloc *sévérité* est plus tendu : $\\mu$ monte à r_hat 1.03, et surtout $\\sigma$ — ess_bulk 44, ess_tail 32, intervalle [0.10, 0.95] autour d'une moyenne de 0.43 — est **mal identifié** plutôt que mal échantillonné : avec 7 à 106 sinistres par segment, $\\sum \\log S$ porte beaucoup d'information sur la moyenne mais très peu sur la dispersion. Le modèle apprend $\\sigma \\approx 0.43$ là où la vérité générationnelle est 0.70. Et c'est précisément pourquoi la prime reste utilisable : les erreurs sur $\\sigma$ et sur $\\mu$ se compensent en partie dans la combinaison $\\mu + \\sigma^2/2$ qui entre dans $\\pi_k$, et le RMSE global de cette section (0.2556, meilleur des trois stratégies) atteste que la quantité *utile* est bien estimée même quand un hyperparamètre ne l'est pas. Leçon générale du bayésien hiérarchique : diagnostiquer les paramètres un à un, mais juger sur la quantité de décision.\n", + "**Lecture du tableau ci-dessus.** Le bloc *fréquence* est propre : `log_lam0` (r_hat 1.00, ess_bulk 687) et `tau_lam` (1.01, 527) explorent sans difficulté. Le bloc *sévérité* est plus tendu : $\\mu$ monte à r_hat 1.03, et surtout $\\sigma$ — ess_bulk 44, ess_tail 32, intervalle [0.10, 0.95] autour d'une moyenne de 0.43 — est **faiblement identifié et insuffisamment échantillonné dans ce run** : l'intervalle large porte la faible identification (avec 7 à 106 sinistres par segment, $\\sum \\log S$ porte beaucoup d'information sur la moyenne mais très peu sur la dispersion), et les ESS bas portent un défaut de mélange que la paramétrisation non centrée atténue sans le nettoyer. Le modèle apprend $\\sigma \\approx 0.43$ là où la vérité générationnelle est 0.70. Et c'est précisément pourquoi la prime reste utilisable : les erreurs sur $\\sigma$ et sur $\\mu$ se compensent en partie dans la combinaison $\\mu + \\sigma^2/2$ qui entre dans $\\pi_k$, et le RMSE global de cette section (0.2556, meilleur des trois stratégies) est encourageant sur la quantité *utile* — mais un score ponctuel ne remplace pas un posterior convergé : il ne clôt pas le défaut d'échantillonnage de $\\sigma$. Leçon générale du bayésien hiérarchique : diagnostiquer les paramètres un à un, et lire la quantité de décision comme un indicateur — jamais comme une validation qui dispenserait de diagnostics propres.\n", "\n", "## 7. La prime pure postérieure (partial pooling)\n", "\n",