Commit Graph

13 Commits

Author SHA1 Message Date
e6f3853426 feat(finess): whitelist de mono-mots distinctifs courts (EMBRUNS, etc.)
Le matcher Aho-Corasick FINESS rejetait tous les mono-mots < 10 chars pour
éviter les faux positifs. Conséquence : EMBRUNS (7 chars), présent dans
etablissements_distinctifs.txt, était ignoré et devait être forcé en YAML
(LES EMBRUNS, REED LES EMBRUNS, EMBRUNS BIDART, regex [Ee]mbruns).

Nouveau fichier data/finess/mono_mots_distinctifs.txt contenant la whitelist
curée des mono-mots courts considérés comme distinctifs. Maintenance manuelle
(un mot par ligne, commentaires autorisés). Le matcher accepte un mono-mot
< 10 chars uniquement s'il est dans cette whitelist.

Initialisation : embruns, embrun (documents CHCB "Les Embruns").

Validation :
- _FINESS_AC matche maintenant "les embruns quelque part" et "embruns seul"
- Pas de régression sur trackare-18007562 (122 hits)

Après ce fix + futurs, on pourra retirer LES EMBRUNS / REED LES EMBRUNS /
EMBRUNS BIDART et regex [Ee]mbruns de force_mask_terms du YAML.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 09:35:16 +02:00
fd95ae5f2a fix(finess): inclure les entjur + supprimer code mort _FINESS_ETAB_NAMES
Deux corrections exploitant mieux les gazetteers FINESS/INSEE pour réduire la
dépendance au YAML force_mask_terms.

1. scripts/build_finess_gazetteers.py : ne lisait que col 1 (finess_et) du CSV.
   Les col 2 (entjur, entité juridique) étaient ignorés. ~48k numéros
   juridiques manqués, dont 640780417 (CHCB entjur) forcé en YAML à cause
   de cette lacune. Fix : lecture col 1 + col 2 avec déduplication.
   Régénération : 101 941 → 150 436 numéros (+48 495).

2. anonymizer_core_refactored_onnx.py :
   - _FINESS_ETAB_NAMES (122k noms) chargé mais jamais consulté après le
     refactoring NER-first (le matching passe par l'Aho-Corasick sur
     etablissements_distinctifs.txt). Suppression → -122k entrées RAM.
   - _INSEE_PRENOMS (lowercase) et _INSEE_PRENOMS_SET (uppercase sans accents)
     lisaient deux fois le même fichier prenoms_france.txt. Fusion en une
     seule passe disque, les deux formes dérivées en mémoire. -36k lectures.

Validation :
- 640780417 présent dans _FINESS_NUMBERS après rebuild
- 122 hits sur trackare-18007562 (non-régression)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 09:33:07 +02:00
59acf390f4 refactor: externaliser DPI labels et companion blacklist (modifiables sans recompiler)
Suite de l'externalisation des règles. Trois listes étaient codées en dur dans
anonymizer_core_refactored_onnx.py et impossibles à modifier par les
établissements sans recompiler :

- _NEVER_MASK_AS_NAME (12 entrées) — labels DPI structurels
- _DPI_LABELS_BLACKLIST (14 entrées, doublon partiel du précédent)
- _COMPANION_BLACKLIST (~75 entrées) — spécialités, labos pharma, mots ambigus

Les deux premières fusionnées dans data/dpi_labels_blacklist.txt (11 entrées
uniques, comparaison case-insensitive). La troisième dans
data/companion_blacklist.txt (75 entrées, comparaison uppercase).

Ajout de deux clés YAML pour enrichissement par établissement :
- additional_dpi_labels (ex: "Service", "Statut")
- additional_companion_blacklist (ex: spécialités locales)

Les 3 niveaux cumulatifs habituels s'appliquent : code (vide) → fichiers data/
→ YAML config. Chargement au démarrage avec log INFO du nombre d'entrées.

Test trackare-18007562-23054899 : 122 hits, 0 régression, 0 DPI label masqué
comme NOM.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 10:26:18 +02:00
2f19f7c470 fix: DR. Ute (3 chars), SAINT-GERMES composé, SODIUM MACO/BAX pharma
- force_names bypass le seuil 4 chars (prénoms courts après Dr/Mme : Ute, Eva)
- SAINT seul = bloqué, SAINT-xxx composé = accepté comme nom
- Labos pharma ajoutés aux stop-words + companion blacklist :
  MACO, AGUETTANT, RENAUDIN, ARROW, BIOGARAN, MYLAN, TEVA, ZENTIVA
- Score : 99.8/100 (amélioration, "Sie" corrigé)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 15:17:37 +02:00
2a4b9d79a1 Revert "refactor: réduction stop-words manuels — NER cross-validation suffit"
This reverts commit fb7896f88d.
2026-03-31 11:04:51 +02:00
fb7896f88d refactor: réduction stop-words manuels — NER cross-validation suffit
La cross-validation NER (_cross_validate_name_candidates) gère désormais
les décisions contextuelles nom/terme-médical. Les stop-words purement
médicaux sont supprimés :

- data/stopwords_manuels.txt : 1307 → 233 entrées (uniquement les mots
  ambigus qui sont aussi des noms/prénoms INSEE)
- _MEDICAL_STOP_WORDS_SET hardcodé : ~400 → 80 entrées essentielles
  (mots courts, formes galéniques, titres hospitaliers)
- Les enrichissements BDPM (~7300), edsnlp (~2000) et fichier externe
  sont conservés tels quels

Score qualité inchangé : 100/100 (A+), 0 fuite, 0 faux positif.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 09:26:54 +02:00
ac5c35ae2d feat: externalisation des listes — stop-words et villes modifiables sans code
Toutes les listes de règles sont maintenant modifiables sans toucher
au code Python :

Fichiers de données (data/) :
  - stopwords_manuels.txt : 1307 termes médicaux/techniques
  - villes_blacklist.txt : 117 communes à ne pas matcher
  - medicaments_stopwords.txt : 7312 médicaments BDPM (existant)
  - Chargés automatiquement au démarrage

Config YAML (dictionnaires.yml) :
  - additional_stopwords : mots supplémentaires par établissement
  - additional_villes_blacklist : villes supplémentaires
  - whitelist_phrases : phrases à ne jamais anonymiser
  - force_mask_terms : mots à toujours masquer

Chaîne de chargement : code dur → fichiers data/ → YAML config
Les 3 niveaux se cumulent (union).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 07:45:42 +02:00
49ff464e6e feat: réduction FP + gazetteers adresses FINESS + batch parallèle + corrections multi-axes
- Token min length relevé de 2-3 → 4 chars (élimine FP EPO, IRC, SIB...)
- Stop-words enrichis : acronymes médicaux 3 lettres, termes pharma, soins infirmiers
- BDPM stop-words : ~7300 noms commerciaux + DCI/substances actives
- Gazetteers adresses FINESS : 63K patterns Aho-Corasick (position-preserving normalization)
- Filtre contextuel anatomique pour FINESS établissements
- Nouvelles regex : RE_CIVILITE_COMMA_LIST, RE_EXTRACT_NOM_UTILISE, RE_EXTRACT_PRENOM,
  RE_NUM_EXAMEN_PATIENT, RE_ADRESSE_LIEU_DIT, RE_CIVILITE_INITIALE, Dr X.NOM
- URLs complètes (RE_URL) + détection multiline
- N° venue inversé (layout-aware) + EPISODE/NDA dans _CRITICAL_PII_TYPES
- HospitalFilter désactivé pour ADRESSE/TEL/VILLE/EPISODE (identifient le patient)
- Batch silver export parallélisé (multiprocessing spawn, N workers)
- Seuil sur-masquage relevé à 8%, server.py enrichi (source regex/ner)
- Blacklist villes : COURANT, PARIS ; contexte villes étendu (UHCD, spécialités)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 09:26:56 +01:00
c9572c383a feat(phase2): Fine-tuning CamemBERT-bio v2 (F1=0.90) + enrichissement données
- Fine-tuning camembert-bio-base : F1=0.903, Recall=0.930 (vs 0.89/0.85)
- Data augmentation : substitution noms INSEE (219K patronymes, x3 copies)
- Hard negatives BDPM (5.7K médicaments) + QUAERO (1319 termes médicaux)
- Annotations silver enrichies par gazetteers (+612 VILLE, +5 HOPITAL)
- Export silver avec support multi-répertoires (--extra-dir)
- Gazetteers QUAERO : CHEM, DISO, PROC, ANAT depuis DrBenchmark/QUAERO
- Gazetteers INSEE : noms de famille fréquents (96K) et complets (219K)
- Batch silver 1194 PDFs (run_batch_silver_export.py) pour dataset v3

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 02:06:08 +01:00
7a2af5c905 feat(phase2): Détection établissements par Aho-Corasick sur 108K noms FINESS
- Nouveau script build_finess_gazetteers.py : extraction noms distinctifs, villes, numéros depuis CSV open data
- Automate Aho-Corasick (pyahocorasick) pour matching multi-pattern en ~1.7ms/page
- 108K patterns indexés (noms composés >= 8 chars, mots uniques >= 10 chars)
- Blacklist mots génériques (clinique, pharmacie, etc.) et stop words médicaux
- Normalisation position-preserving (sans accents, même longueur)
- Construction lazy de l'AC (après chargement des stop words)
- Intégration dans _mask_line_by_regex et selective_rescan
- Nouveau gazetteer villes_finess.txt (11,660 villes)
- Résultats : "Girandières" → masqué, "Côte Basque" → masqué, 0 FP sur termes médicaux courants

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 22:56:43 +01:00
26b210607c feat(phase2): Gazetteers FINESS 102K établissements + fine-tuning CamemBERT-bio F1=89%
Gazetteers FINESS (data.gouv.fr open data):
- 102K numéros FINESS → détection par lookup exact dans _mask_admin_label + selective_rescan
- 122K noms d'établissements, 113K téléphones, 76K adresses (disponibles)
- Un nombre 9 chiffres matchant un vrai FINESS est masqué même sans label "FINESS"

Fine-tuning CamemBERT-bio (almanach/camembert-bio-base):
- Export silver annotations réécrit : alignement original↔pseudonymisé (difflib)
  → 6862 entités B- (vs 3344 avec l'ancien audit-only) sur 222K tokens
- Sliding windows (200 tokens, stride 100) pour documents longs
- WeightedNERTrainer avec class weights cappés (max 10x) + label smoothing
- Résultat: Precision=88.1%, Recall=89.8%, F1=88.9% (20 epochs, lr=1e-5)
- Modèle sauvegardé dans models/camembert-bio-deid/best (non commité)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 13:27:37 +01:00
6e0e8c7312 feat(phase2): Gazetteers INSEE (36K prénoms + 34K communes) + silver annotations
- Prénoms INSEE renforcent la confiance NER (prénom connu → ne pas filtrer)
- Communes INSEE disponibles pour distinction ville/nom de famille
- Export 29 fichiers silver annotations (252K tokens, 12.8K entités) pour fine-tuning

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 12:03:17 +01:00
26ac02b0cb feat(phase2): Multi-signal NER — BDPM gazetteers, confiance EDS, safe patterns, GLiNER
Chantier 1: Intégration BDPM (5737 médicaments officiels) dans medication whitelist
Chantier 2: Safe patterns contextuels (dosages mg/mL/cpr, formes pharma, même ligne)
Chantier 3: Scores de confiance NER réels (edsnlp 0.20 ner_confidence_score)
Chantier 4: GLiNER zero-shot (urchade/gliner_multi_pii-v1) en vote croisé
Chantier 5: Scripts export silver annotations + fine-tuning CamemBERT-bio

0 fuite, 0 régression, -18 FP supplémentaires éliminés.
Sécurité: GLiNER ne peut rejeter que si confiance NER < 0.70.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 12:01:46 +01:00