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>
This commit is contained in:
2026-03-09 13:27:37 +01:00
parent 6e0e8c7312
commit 26b210607c
36 changed files with 447533 additions and 62915 deletions

View File

@@ -150,6 +150,55 @@ def _load_insee_gazetteers():
_load_insee_gazetteers() _load_insee_gazetteers()
# ----------------- Gazetteer FINESS (établissements de santé) -----------------
_FINESS_NUMBERS: set = set() # numéros FINESS 9 chiffres
_FINESS_ETAB_NAMES: set = set() # noms d'établissements (lowercase)
_FINESS_TELEPHONES: set = set() # téléphones 10 chiffres
def _load_finess_gazetteers():
"""Charge les gazetteers FINESS (établissements, numéros, téléphones)."""
global _FINESS_NUMBERS, _FINESS_ETAB_NAMES, _FINESS_TELEPHONES
data_dir = Path(__file__).parent / "data" / "finess"
# Numéros FINESS
finess_path = data_dir / "finess_numbers.txt"
if finess_path.exists():
try:
_FINESS_NUMBERS = {
line.strip() for line in finess_path.read_text(encoding="utf-8").splitlines()
if line.strip()
}
log.info(f"Gazetteer FINESS numéros: {len(_FINESS_NUMBERS)} entrées")
except Exception as e:
log.warning(f"Erreur chargement FINESS numéros: {e}")
# Noms d'établissements (pour détection HOPITAL)
noms_path = data_dir / "etablissements_noms.txt"
if noms_path.exists():
try:
_FINESS_ETAB_NAMES = {
line.strip().lower() for line in noms_path.read_text(encoding="utf-8").splitlines()
if line.strip() and len(line.strip()) >= 6
}
log.info(f"Gazetteer FINESS noms: {len(_FINESS_ETAB_NAMES)} entrées")
except Exception as e:
log.warning(f"Erreur chargement FINESS noms: {e}")
# Téléphones (pour validation)
tel_path = data_dir / "telephones.txt"
if tel_path.exists():
try:
_FINESS_TELEPHONES = {
line.strip() for line in tel_path.read_text(encoding="utf-8").splitlines()
if line.strip()
}
log.info(f"Gazetteer FINESS téléphones: {len(_FINESS_TELEPHONES)} entrées")
except Exception as e:
log.warning(f"Erreur chargement FINESS téléphones: {e}")
_load_finess_gazetteers()
# ----------------- Whitelists Médicales ----------------- # ----------------- Whitelists Médicales -----------------
_MEDICAL_STRUCTURAL_TERMS = set() _MEDICAL_STRUCTURAL_TERMS = set()
_MEDICATION_WHITELIST = set() _MEDICATION_WHITELIST = set()
@@ -1030,11 +1079,23 @@ def _apply_overrides(line: str, audit: List[PiiHit], page_idx: int, cfg: Dict[st
return line return line
RE_BARE_9DIGITS = re.compile(r"\b(\d{9})\b")
def _mask_admin_label(line: str, audit: List[PiiHit], page_idx: int) -> str: def _mask_admin_label(line: str, audit: List[PiiHit], page_idx: int) -> str:
m = RE_FINESS.search(line) m = RE_FINESS.search(line)
if m: if m:
val = m.group(1); audit.append(PiiHit(page_idx, "FINESS", val, PLACEHOLDERS["FINESS"])) val = m.group(1); audit.append(PiiHit(page_idx, "FINESS", val, PLACEHOLDERS["FINESS"]))
return RE_FINESS.sub(lambda _: f"FINESS : {PLACEHOLDERS['FINESS']}", line) return RE_FINESS.sub(lambda _: f"FINESS : {PLACEHOLDERS['FINESS']}", line)
# Détection FINESS par gazetteer : nombre 9 chiffres qui matche un vrai numéro FINESS
if _FINESS_NUMBERS:
for m9 in RE_BARE_9DIGITS.finditer(line):
if m9.group(1) in _FINESS_NUMBERS:
val = m9.group(1)
audit.append(PiiHit(page_idx, "FINESS", val, PLACEHOLDERS["FINESS"]))
line = line.replace(val, PLACEHOLDERS["FINESS"], 1)
return line
m = RE_OGC.search(line) m = RE_OGC.search(line)
if m: if m:
val = m.group(1); audit.append(PiiHit(page_idx, "OGC", val, PLACEHOLDERS["OGC"])) val = m.group(1); audit.append(PiiHit(page_idx, "OGC", val, PLACEHOLDERS["OGC"]))
@@ -2012,6 +2073,11 @@ def selective_rescan(text: str, cfg: Dict[str, Any] | None = None) -> str:
protected = RE_EPISODE.sub(PLACEHOLDERS["EPISODE"], protected) protected = RE_EPISODE.sub(PLACEHOLDERS["EPISODE"], protected)
# N° RPPS # N° RPPS
protected = RE_RPPS.sub(PLACEHOLDERS["RPPS"], protected) protected = RE_RPPS.sub(PLACEHOLDERS["RPPS"], protected)
# FINESS par gazetteer (nombres 9 chiffres matchant un vrai numéro FINESS)
if _FINESS_NUMBERS:
def _rescan_finess(m: re.Match) -> str:
return PLACEHOLDERS["FINESS"] if m.group(1) in _FINESS_NUMBERS else m.group(0)
protected = RE_BARE_9DIGITS.sub(_rescan_finess, protected)
# Établissements # Établissements
protected = RE_ETABLISSEMENT.sub(PLACEHOLDERS["ETAB"], protected) protected = RE_ETABLISSEMENT.sub(PLACEHOLDERS["ETAB"], protected)
protected = RE_HOPITAL_VILLE.sub(PLACEHOLDERS["ETAB"], protected) protected = RE_HOPITAL_VILLE.sub(PLACEHOLDERS["ETAB"], protected)

76414
data/finess/adresses.txt Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

101941
data/finess/finess_numbers.txt Normal file

File diff suppressed because it is too large Load Diff

113247
data/finess/telephones.txt Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,42 +1,62 @@
[MASK] O Centre B-HOPITAL
Hospitalier I-HOPITAL
de I-HOPITAL
la I-HOPITAL
Côte I-HOPITAL
Basque I-HOPITAL
LABORATOIRE O LABORATOIRE O
de O de O
BIOLOGIE O BIOLOGIE O
MEDICALE O MEDICALE O
[ADRESSE] B-ADRESSE 13 B-ADRESSE
[CODE_POSTAL] B-ZIP avenue I-ADRESSE
de I-ADRESSE
l'interne B-ZIP
Jacques I-ZIP
Loëb I-ZIP
64109 I-ZIP
BAYONNE O BAYONNE O
- O - O
Tel O Tel O
: O : O
[TEL] B-TEL 0559443674 B-TEL
Microbiologie O Microbiologie O
Dr O Dr O
[NOM] B-PER JAOUEN B-PER
Anne-Christine I-PER
Hématologie O Hématologie O
Dr O Dr O
[NOM] B-PER MENARD-DEROURE B-PER
Fanny I-PER
(chef O (chef O
de O de O
service) O service) O
Dr O Dr O
[NOM] B-PER BENARD B-PER
Yohan I-PER
Dr O Dr O
[NOM] B-PER GUILLEMAUD B-PER
Julien I-PER
Dr O Dr O
[NOM] B-PER MONIER B-PER
Laurie I-PER
Dr O Dr O
[NOM] B-PER DECOEUR B-PER
Lucie I-PER
Dr O Dr O
[NOM] B-PER LEYSSENE B-PER
David I-PER
Biochimie O Biochimie O
Dr O Dr O
[NOM] B-PER CURUTCHET-BURTIN B-PER
Marie-Laure I-PER
Dr O Dr O
[NOM] B-PER SEGUES B-PER
Rémi I-PER
Assistante O Assistante O
Dr O Dr O
[NOM] B-PER BEVIERE B-PER
Marion I-PER
Diffusé O Diffusé O
le O le O
: O : O
@@ -46,14 +66,14 @@ rendu O
Complet O Complet O
05/12/2023 O 05/12/2023 O
10.40 O 10.40 O
[NOM] B-PER SIMONET B-PER
[NOM] B-PER Marie I-PER
[NOM] B-PER lise I-PER
Nom O Nom O
usuel O usuel O
: O : O
[DATE_NAISSANCE] B-DATE_NAISSANCE 13/09/1948 B-DATE_NAISSANCE
[NOM] B-PER OYARCABAL B-PER
URGENCES O URGENCES O
75 O 75 O
a O a O
@@ -65,42 +85,36 @@ F O
23232115 O 23232115 O
IPP O IPP O
: O : O
[IPP] B-IPP BA125020 B-IPP
N° O N° O
venue O venue O
: O : O
DEMANDE O DEMANDE O
N° O N° O
[DOSSIER] B-NDA 2300261164 B-NDA
Prescrit O Prescrit O
le O le O
: O : O
03/12/2023 O 03/12/2023 O
11 O 11:44 O
: O
44 O
Par O Par O
: O : O
[NOM] B-PER TEILLARD B-PER
[NOM] B-PER Lucie I-PER
Prélevé O Prélevé O
le O le O
: O : O
03/12/2023 O 03/12/2023 O
11 O 11:47 O
: O
47 O
Par O Par O
: O : O
[NOM] B-PER VIGNES B-PER
[NOM] B-PER Sophie I-PER
Reçu O Reçu O
le O le O
: O : O
03/12/2023 O 03/12/2023 O
12 O 12:10 O
: O
10 O
Résultat O Résultat O
Borne O Borne O
BACTERIOLOGIE O BACTERIOLOGIE O
@@ -278,29 +292,31 @@ biologiste O
Page O Page O
1/2 O 1/2 O
Dr. O Dr. O
[NOM] B-PER Anne B-PER
Christine I-PER
JAOUEN I-PER
N° O N° O
8-3188 O 8-3188 O
Portée O Portée O
disponible O disponible O
sur O sur O
[ETABLISSEMENT] O www.cofrac.fr B-PER
[NOM] B-PER SIMONET I-PER
[NOM] B-PER Marie I-PER
[NOM] B-PER lise I-PER
Nom O Nom O
usuel O usuel O
: O : O
[NOM] B-PER OYARCABAL B-PER
DDN O DDN O
: O : O
SEXE O SEXE O
: O : O
[DATE_NAISSANCE] B-DATE_NAISSANCE 13/09/1948 B-DATE_NAISSANCE
F O F O
DEMANDE O DEMANDE O
N° O N° O
[DOSSIER] B-NDA 2300261164 B-NDA
Résultat O Résultat O
Antibiogramme O Antibiogramme O
. O . O
@@ -500,7 +516,7 @@ N° O
Portée O Portée O
disponible O disponible O
sur O sur O
[ETABLISSEMENT] O www.cofrac.fr O
Validé O Validé O
et O et O
diffusé O diffusé O
@@ -513,4 +529,6 @@ biologiste O
Page O Page O
2/2 O 2/2 O
Dr. O Dr. O
[NOM] B-PER Anne B-PER
Christine I-PER
JAOUEN I-PER

View File

@@ -1,8 +1,14 @@
[MASK] O Centre B-HOPITAL
Hospitalier I-HOPITAL
de I-HOPITAL
la I-HOPITAL
Côte I-HOPITAL
Basque I-HOPITAL
Anesthésiste O Anesthésiste O
: O : O
Dr O Dr O
[NOM] B-PER DUFOUR B-PER
Eric I-PER
DOSSIER O DOSSIER O
DE O DE O
CONSULTATION O CONSULTATION O
@@ -15,24 +21,26 @@ Date O
Nom O Nom O
: O : O
M. O M. O
[NOM] B-PER URRUTY B-PER
Joseph I-PER
Né(e) O Né(e) O
le O le O
: O : O
[DATE_NAISSANCE] B-DATE_NAISSANCE 08/05/1950 B-DATE_NAISSANCE
72 O 72 O
ans O ans O
N°Ipp O N°Ipp O
: O : O
[IPP] B-IPP S1032021 B-IPP
N° O N° O
Csult O
: O : O
[DOSSIER] B-NDA 23056022 B-NDA
/ O / O
Nom O Nom O
naiss. O naiss. O
: O : O
[DOSSIER] B-NDA 23056022 B-NDA
Poids O Poids O
: O : O
85 O 85 O
@@ -48,14 +56,18 @@ Profession O
: O : O
Adresse O Adresse O
: O : O
[ADRESSE] B-ADRESSE 65 B-ADRESSE
[CODE_POSTAL] B-ZIP LOTISSEMENT I-ADRESSE
HITTA I-ADRESSE
GOTEIN-LI B-ZIP
64130 I-ZIP
GOTEIN-LIBARRENX I-ZIP
N° O N° O
Tél O Tél O
: O : O
[TEL] B-TEL 0681460115 B-TEL
à O à O
[TEL] B-TEL 09:17 B-TEL
Spécialiste O Spécialiste O
: O : O
Date O Date O
@@ -69,11 +81,13 @@ Motif O
d'admission O d'admission O
: O : O
NÉPHRO O NÉPHRO O
[NOM] B-PER URÉTÉRECTOMIE B-PER
COELIO I-PER
Opérateur O Opérateur O
: O : O
Dr O Dr O
[NOM] B-PER MASCLE B-PER
Laurent I-PER
Prévenir O Prévenir O
: O : O
Mémo O Mémo O
@@ -105,15 +119,14 @@ le O
: O : O
Service O Service O
: O : O
__ O __:__ O
: O
__ O
__/__/__ O __/__/__ O
Antécédents O Antécédents O
/ O / O
Traitements O Traitements O
Examen O Examen O
[ETABLISSEMENT] O clinique O
Décisions O
/ O / O
Prescriptions O Prescriptions O
ATCD O ATCD O
@@ -132,8 +145,7 @@ cardio-vasculaires O
Derniers O Derniers O
examens/Epreuve O examens/Epreuve O
d'effort O d'effort O
2020 O 2020: O
: O
normale O normale O
ATCD O ATCD O
pulmonaires O pulmonaires O
@@ -181,8 +193,7 @@ Histoire O
de O de O
la O la O
maladie O maladie O
HDM O HDM: O
: O
lésion O lésion O
de O de O
l'uretère O l'uretère O
@@ -379,15 +390,13 @@ Récent(s) O
Autre O Autre O
[le O [le O
17/04 O 17/04 O
Na O Na: O
: O
144 O 144 O
K: O K: O
4.6 O 4.6 O
Créat: O Créat: O
80 O 80 O
DFG O DFG: O
: O
84 O 84 O
Hb: O Hb: O
14.4 O 14.4 O
@@ -425,9 +434,7 @@ jeun O
le O le O
25/04/2023 O 25/04/2023 O
à O à O
00 O 00:00 O
: O
00 O
Merci O Merci O
de O de O
proposer O proposer O
@@ -489,16 +496,15 @@ Le O
24 O 24 O
Avril O Avril O
2023 O 2023 O
17 O 17:07 O
: O
07 O
Page O Page O
: O : O
1/2 O 1/2 O
Anesthésiste O Anesthésiste O
: O : O
Dr O Dr O
[NOM] B-PER DUFOUR B-PER
Eric I-PER
DOSSIER O DOSSIER O
DE O DE O
CONSULTATION O CONSULTATION O
@@ -511,24 +517,26 @@ Date O
Nom O Nom O
: O : O
M. O M. O
[NOM] B-PER URRUTY B-PER
Joseph I-PER
Né(e) O Né(e) O
le O le O
: O : O
[DATE_NAISSANCE] B-DATE_NAISSANCE 08/05/1950 B-DATE_NAISSANCE
72 O 72 O
ans O ans O
N°Ipp O N°Ipp O
: O : O
[IPP] B-IPP S1032021 B-IPP
N° O N° O
Csult O
: O : O
[DOSSIER] B-NDA 23056022 B-NDA
/ O / O
Nom O Nom O
naiss. O naiss. O
: O : O
[DOSSIER] B-NDA 23056022 B-NDA
Poids O Poids O
: O : O
85 O 85 O
@@ -544,12 +552,16 @@ Profession O
: O : O
Adresse O Adresse O
: O : O
[ADRESSE] B-ADRESSE 65 B-ADRESSE
[CODE_POSTAL] B-ZIP LOTISSEMENT I-ADRESSE
HITTA I-ADRESSE
GOTEIN-LI B-ZIP
64130 I-ZIP
GOTEIN-LIBARRENX I-ZIP
N° O N° O
Tél O Tél O
: O : O
[TEL] B-TEL 0681460115 B-TEL
(Bienvenu) O (Bienvenu) O
per-opératoire O per-opératoire O
: O : O
@@ -589,40 +601,41 @@ Le O
24 O 24 O
Avril O Avril O
2023 O 2023 O
17 O 17:07 O
: O
07 O
Page O Page O
: O : O
2/2 O 2/2 O
Anesthésiste O Anesthésiste O
: O : O
Dr O Dr O
[NOM] B-PER DUFOUR B-PER
Eric I-PER
Prémédication O Prémédication O
IPP O I.P.P. O
: O : O
[IPP] B-IPP S1032021 B-IPP
Patient O Patient O
: O : O
[NOM] B-PER URRUTY B-PER
[NOM] B-PER JOSEPH I-PER
[DATE_NAISSANCE] B-DATE_NAISSANCE né(e) O
N° O
: O
[DOSSIER] B-NDA
Né(e) O
le O le O
: O : O
[DATE_NAISSANCE] B-DATE_NAISSANCE 08/05/1950 B-DATE_NAISSANCE
N° I-DATE_NAISSANCE
Interv I-DATE_NAISSANCE
: I-DATE_NAISSANCE
23056022 I-DATE_NAISSANCE
Né(e) I-DATE_NAISSANCE
le I-DATE_NAISSANCE
: I-DATE_NAISSANCE
08/05/1950 I-DATE_NAISSANCE
72 O 72 O
ans O ans O
Date O Date O
: O : O
24/04/2023 O 24/04/2023 O
16 O 16:41 O
: O
41 O
Consigne(s) O Consigne(s) O
IDE O IDE O
PREPARATIONS O PREPARATIONS O
@@ -631,9 +644,7 @@ jeun O
le O le O
25/04/2023 O 25/04/2023 O
à O à O
00 O 00:00 O
: O
00 O
Merci O Merci O
de O de O
proposer O proposer O
@@ -744,9 +755,7 @@ Le O
24 O 24 O
Avril O Avril O
2023 O 2023 O
17 O 17:07 O
: O
07 O
Page O Page O
: O : O
1/1 O 1/1 O

View File

@@ -1,8 +1,14 @@
[MASK] O Centre B-HOPITAL
Hospitalier I-HOPITAL
de I-HOPITAL
la I-HOPITAL
Côte I-HOPITAL
Basque I-HOPITAL
Anesthésiste O Anesthésiste O
: O : O
Dr O Dr O
[NOM] B-PER KARAM B-PER
Lydia I-PER
DOSSIER O DOSSIER O
DE O DE O
CONSULTATION O CONSULTATION O
@@ -15,24 +21,26 @@ Date O
Nom O Nom O
: O : O
M. O M. O
[NOM] B-PER GASTESI B-PER
Michel I-PER
Né(e) O Né(e) O
le O le O
: O : O
[DATE_NAISSANCE] B-DATE_NAISSANCE 01/02/1952 B-DATE_NAISSANCE
71 O 71 O
ans O ans O
N°Ipp O N°Ipp O
: O : O
[IPP] B-IPP 20023294 B-IPP
N° O N° O
Csult O
: O : O
[DOSSIER] B-NDA 23605230 B-NDA
/ O / O
Nom O Nom O
naiss. O naiss. O
: O : O
[DOSSIER] B-NDA 23060661 B-NDA
Poids O Poids O
: O : O
87 O 87 O
@@ -48,16 +56,19 @@ Profession O
: O : O
Adresse O Adresse O
: O : O
[ADRESSE] B-ADRESSE 137 B-ADRESSE
[CODE_POSTAL] B-ZIP HAMEAU I-ADRESSE
DE I-ADRESSE
GARLATZETXE B-ZIP
ALAIA I-ZIP
64700 I-ZIP
BIRIATOU I-ZIP
N° O N° O
Tél O Tél O
: O : O
[TEL] B-TEL 0559203820 B-TEL
à O à O
12 O 12:14 O
: O
14 O
Spécialiste O Spécialiste O
: O : O
Date O Date O
@@ -74,7 +85,8 @@ HOLEP O
Opérateur O Opérateur O
: O : O
Dr O Dr O
[NOM] B-PER LAMMERTYN B-PER
Yann I-PER
Prévenir O Prévenir O
: O : O
Mémo O Mémo O
@@ -104,9 +116,7 @@ le O
: O : O
Service O Service O
: O : O
__ O __:__ O
: O
__ O
__/__/__ O __/__/__ O
Thrombo-embolique O Thrombo-embolique O
: O : O
@@ -126,7 +136,8 @@ Antécédents O
/ O / O
Traitements O Traitements O
Examen O Examen O
[ETABLISSEMENT] O clinique O
Décisions O
/ O / O
Prescriptions O Prescriptions O
ATCD O ATCD O
@@ -179,8 +190,7 @@ antiagrégant O
Derniers O Derniers O
examens/Echo O examens/Echo O
01/2021 O 01/2021: O
: O
VG O VG O
non O non O
dilaté O dilaté O
@@ -215,11 +225,10 @@ depuis O
> O > O
1 O 1 O
an O an O
presque O presque; O
: O
suivi O suivi O
Dr O Dr O
[NOM] B-PER Mathieu B-PER
. O . O
Tabac/Sevré O Tabac/Sevré O
@@ -237,8 +246,7 @@ ans O
Examens O Examens O
paracliniques O paracliniques O
récents/EFR O récents/EFR O
11/2022 O 11/2022: O
: O
VEMS O VEMS O
à O à O
124% O 124% O
@@ -286,8 +294,7 @@ Cs O
neuro O neuro O
11/2022 O 11/2022 O
Dr O Dr O
[NOM] B-PER Tollet: B-PER
: O
élocution O élocution O
plus O plus O
harmonieuse. O harmonieuse. O
@@ -367,8 +374,7 @@ d'effort/ O
4 O 4 O
à O à O
7 O 7 O
actif O actif; O
: O
a O a O
repris O repris O
ses O ses O
@@ -558,16 +564,15 @@ Le O
02 O 02 O
Avril O Avril O
2023 O 2023 O
17 O 17:30 O
: O
30 O
Page O Page O
: O : O
1/3 O 1/3 O
Anesthésiste O Anesthésiste O
: O : O
Dr O Dr O
[NOM] B-PER KARAM B-PER
Lydia I-PER
DOSSIER O DOSSIER O
DE O DE O
CONSULTATION O CONSULTATION O
@@ -580,24 +585,26 @@ Date O
Nom O Nom O
: O : O
M. O M. O
[NOM] B-PER GASTESI B-PER
Michel I-PER
Né(e) O Né(e) O
le O le O
: O : O
[DATE_NAISSANCE] B-DATE_NAISSANCE 01/02/1952 B-DATE_NAISSANCE
71 O 71 O
ans O ans O
N°Ipp O N°Ipp O
: O : O
[IPP] B-IPP 20023294 B-IPP
N° O N° O
Csult O
: O : O
[DOSSIER] B-NDA 23605230 B-NDA
/ O / O
Nom O Nom O
naiss. O naiss. O
: O : O
[DOSSIER] B-NDA 23060661 B-NDA
Poids O Poids O
: O : O
87 O 87 O
@@ -613,12 +620,17 @@ Profession O
: O : O
Adresse O Adresse O
: O : O
[ADRESSE] B-ADRESSE 137 B-ADRESSE
[CODE_POSTAL] B-ZIP HAMEAU I-ADRESSE
DE I-ADRESSE
GARLATZETXE B-ZIP
ALAIA I-ZIP
64700 I-ZIP
BIRIATOU I-ZIP
N° O N° O
Tél O Tél O
: O : O
[TEL] B-TEL 0559203820 B-TEL
Interrogatoire O Interrogatoire O
/ O / O
Autorisation O Autorisation O
@@ -963,12 +975,8 @@ biologique O
: O : O
Résultat(s) O Résultat(s) O
récent(s) O récent(s) O
(N O (N:Normal, O
: O A:Anormal) O
Normal, O
A O
: O
Anormal) O
: O : O
- O - O
Créat O Créat O
@@ -1064,9 +1072,7 @@ jeun O
le O le O
06/04/2023 O 06/04/2023 O
à O à O
00 O 00:00 O
: O
00 O
Merci O Merci O
de O de O
proposer O proposer O
@@ -1121,16 +1127,15 @@ Le O
02 O 02 O
Avril O Avril O
2023 O 2023 O
17 O 17:30 O
: O
30 O
Page O Page O
: O : O
2/3 O 2/3 O
Anesthésiste O Anesthésiste O
: O : O
Dr O Dr O
[NOM] B-PER KARAM B-PER
Lydia I-PER
DOSSIER O DOSSIER O
DE O DE O
CONSULTATION O CONSULTATION O
@@ -1143,24 +1148,26 @@ Date O
Nom O Nom O
: O : O
M. O M. O
[NOM] B-PER GASTESI B-PER
Michel I-PER
Né(e) O Né(e) O
le O le O
: O : O
[DATE_NAISSANCE] B-DATE_NAISSANCE 01/02/1952 B-DATE_NAISSANCE
71 O 71 O
ans O ans O
N°Ipp O N°Ipp O
: O : O
[IPP] B-IPP 20023294 B-IPP
N° O N° O
Csult O
: O : O
[DOSSIER] B-NDA 23605230 B-NDA
/ O / O
Nom O Nom O
naiss. O naiss. O
: O : O
[DOSSIER] B-NDA 23060661 B-NDA
Poids O Poids O
: O : O
87 O 87 O
@@ -1176,12 +1183,17 @@ Profession O
: O : O
Adresse O Adresse O
: O : O
[ADRESSE] B-ADRESSE 137 B-ADRESSE
[CODE_POSTAL] B-ZIP HAMEAU I-ADRESSE
DE I-ADRESSE
GARLATZETXE B-ZIP
ALAIA I-ZIP
64700 I-ZIP
BIRIATOU I-ZIP
N° O N° O
Tél O Tél O
: O : O
[TEL] B-TEL 0559203820 B-TEL
. O . O
Baby-Noradrénaline O Baby-Noradrénaline O
@@ -1194,13 +1206,12 @@ PRE-ANESTHESIQUE O
Date O Date O
: O : O
02/04/2023 O 02/04/2023 O
15 O 15:02 O
: O
02 O
Anesthésiste O Anesthésiste O
: O : O
Dr O Dr O
[NOM] B-PER LEONARD B-PER
Grégoire I-PER
VPA O VPA O
/ O / O
Eléments O Eléments O
@@ -1242,40 +1253,41 @@ Le O
02 O 02 O
Avril O Avril O
2023 O 2023 O
17 O 17:30 O
: O
30 O
Page O Page O
: O : O
3/3 O 3/3 O
Anesthésiste O Anesthésiste O
: O : O
Dr O Dr O
[NOM] B-PER KARAM B-PER
Lydia I-PER
Prémédication O Prémédication O
IPP O I.P.P. O
: O : O
[IPP] B-IPP 20023294 B-IPP
Patient O Patient O
: O : O
[NOM] B-PER GASTESI B-PER
[NOM] B-PER MICHEL I-PER
[DATE_NAISSANCE] B-DATE_NAISSANCE né(e) O
N° O
: O
[DOSSIER] B-NDA
Né(e) O
le O le O
: O : O
[DATE_NAISSANCE] B-DATE_NAISSANCE 01/02/1952 B-DATE_NAISSANCE
N° I-DATE_NAISSANCE
Interv I-DATE_NAISSANCE
: I-DATE_NAISSANCE
23060661 I-DATE_NAISSANCE
Né(e) I-DATE_NAISSANCE
le I-DATE_NAISSANCE
: I-DATE_NAISSANCE
01/02/1952 I-DATE_NAISSANCE
71 O 71 O
ans O ans O
Date O Date O
: O : O
29/03/2023 O 29/03/2023 O
11 O 11:40 O
: O
40 O
Consigne(s) O Consigne(s) O
IDE O IDE O
PREPARATIONS O PREPARATIONS O
@@ -1284,9 +1296,7 @@ jeun O
le O le O
06/04/2023 O 06/04/2023 O
à O à O
00 O 00:00 O
: O
00 O
Merci O Merci O
de O de O
proposer O proposer O
@@ -1433,9 +1443,7 @@ CP O
- O - O
Articulaire O Articulaire O
-, O -, O
Matin O Matin:1, O
: O
1, O
A O A O
continuer O continuer O
le O le O
@@ -1446,9 +1454,7 @@ azarga O
10/5 O 10/5 O
// O // O
goutte, O goutte, O
Matin O Matin:1, O
: O
1, O
A O A O
continuer O continuer O
le O le O
@@ -1461,9 +1467,7 @@ mg O
- O - O
PO O PO O
-, O -, O
Soir O Soir:10 O
: O
10 O
10 O 10 O
mg O mg O
ezetimibbe O ezetimibbe O
@@ -1473,9 +1477,7 @@ CP O
- O - O
PO O PO O
-, O -, O
Soir O Soir:1, O
: O
1, O
A O A O
continuer O continuer O
jusqu'à O jusqu'à O
@@ -1488,17 +1490,13 @@ CP O
kardegic O kardegic O
75mg O 75mg O
//, O //, O
Matin O Matin:1 O
: O
1 O
monoprost O monoprost O
// O // O
goutte O goutte O
[Oeil O [Oeil O
G], O G], O
Soir O Soir:1, O
: O
1, O
A O A O
continuer O continuer O
jusqu'à O jusqu'à O
@@ -1515,9 +1513,7 @@ CP O
- O - O
PO O PO O
-, O -, O
Matin O Matin:1, O
: O
1, O
Soir:1, O Soir:1, O
A O A O
continuer O continuer O
@@ -1541,9 +1537,7 @@ CP O
- O - O
PO O PO O
-, O -, O
Soir O Soir:1, O
: O
1, O
A O A O
continuer O continuer O
jusqu'à O jusqu'à O
@@ -1558,40 +1552,41 @@ Le O
02 O 02 O
Avril O Avril O
2023 O 2023 O
17 O 17:30 O
: O
30 O
Page O Page O
: O : O
1/2 O 1/2 O
Anesthésiste O Anesthésiste O
: O : O
Dr O Dr O
[NOM] B-PER KARAM B-PER
Lydia I-PER
Prémédication O Prémédication O
IPP O I.P.P. O
: O : O
[IPP] B-IPP 20023294 B-IPP
Patient O Patient O
: O : O
[NOM] B-PER GASTESI B-PER
[NOM] B-PER MICHEL I-PER
[DATE_NAISSANCE] B-DATE_NAISSANCE né(e) O
N° O
: O
[DOSSIER] B-NDA
Né(e) O
le O le O
: O : O
[DATE_NAISSANCE] B-DATE_NAISSANCE 01/02/1952 B-DATE_NAISSANCE
N° I-DATE_NAISSANCE
Interv I-DATE_NAISSANCE
: I-DATE_NAISSANCE
23060661 I-DATE_NAISSANCE
Né(e) I-DATE_NAISSANCE
le I-DATE_NAISSANCE
: I-DATE_NAISSANCE
01/02/1952 I-DATE_NAISSANCE
71 O 71 O
ans O ans O
Date O Date O
: O : O
29/03/2023 O 29/03/2023 O
11 O 11:40 O
: O
40 O
Date O Date O
/ O / O
Heure O Heure O
@@ -1602,9 +1597,7 @@ Le O
02 O 02 O
Avril O Avril O
2023 O 2023 O
17 O 17:30 O
: O
30 O
Page O Page O
: O : O
2/2 O 2/2 O

View File

@@ -1,8 +1,14 @@
[MASK] O Centre B-HOPITAL
Hospitalier I-HOPITAL
de I-HOPITAL
la I-HOPITAL
Côte I-HOPITAL
Basque I-HOPITAL
Anesthésiste O Anesthésiste O
: O : O
Dr O Dr O
[NOM] B-PER LEGRAS B-PER
Claire I-PER
DOSSIER O DOSSIER O
DE O DE O
CONSULTATION O CONSULTATION O
@@ -15,24 +21,26 @@ Date O
Nom O Nom O
: O : O
M. O M. O
[NOM] B-PER PONCABARE B-PER
Jean I-PER
Né(e) O Né(e) O
le O le O
: O : O
[DATE_NAISSANCE] B-DATE_NAISSANCE 17/04/1963 B-DATE_NAISSANCE
60 O 60 O
ans O ans O
N°Ipp O N°Ipp O
: O : O
[IPP] B-IPP S1024244 B-IPP
N° O N° O
Csult O
: O : O
[DOSSIER] B-NDA 23694563 B-NDA
/ O / O
Nom O Nom O
naiss. O naiss. O
: O : O
[DOSSIER] B-NDA 23139653 B-NDA
Poids O Poids O
: O : O
88 O 88 O
@@ -52,9 +60,7 @@ N° O
Tél O Tél O
: O : O
à O à O
12 O 12:11 O
: O
11 O
Spécialiste O Spécialiste O
: O : O
Date O Date O
@@ -102,9 +108,7 @@ le O
: O : O
Service O Service O
: O : O
__ O __:__ O
: O
__ O
__/__/__ O __/__/__ O
Classe O Classe O
ASA O ASA O
@@ -114,7 +118,8 @@ Antécédents O
/ O / O
Traitements O Traitements O
Examen O Examen O
[ETABLISSEMENT] O clinique O
Décisions O
/ O / O
Prescriptions O Prescriptions O
ATCD O ATCD O
@@ -192,7 +197,7 @@ gauche O
Consultation O Consultation O
cardio O cardio O
Dr O Dr O
[NOM] B-PER Minviole B-PER
04/23 O 04/23 O
: O : O
FEVG O FEVG O
@@ -499,16 +504,15 @@ Le O
03 O 03 O
Septembre O Septembre O
2023 O 2023 O
17 O 17:32 O
: O
32 O
Page O Page O
: O : O
1/2 O 1/2 O
Anesthésiste O Anesthésiste O
: O : O
Dr O Dr O
[NOM] B-PER LEGRAS B-PER
Claire I-PER
DOSSIER O DOSSIER O
DE O DE O
CONSULTATION O CONSULTATION O
@@ -521,24 +525,26 @@ Date O
Nom O Nom O
: O : O
M. O M. O
[NOM] B-PER PONCABARE B-PER
Jean I-PER
Né(e) O Né(e) O
le O le O
: O : O
[DATE_NAISSANCE] B-DATE_NAISSANCE 17/04/1963 B-DATE_NAISSANCE
60 O 60 O
ans O ans O
N°Ipp O N°Ipp O
: O : O
[IPP] B-IPP S1024244 B-IPP
N° O N° O
Csult O
: O : O
[DOSSIER] B-NDA 23694563 B-NDA
/ O / O
Nom O Nom O
naiss. O naiss. O
: O : O
[DOSSIER] B-NDA 23139653 B-NDA
Poids O Poids O
: O : O
88 O 88 O
@@ -608,9 +614,7 @@ Prescription O
biologique O biologique O
: O : O
Résultat(s) O Résultat(s) O
(N O (N:Normal, O
: O
Normal, O
A:Anormal) O A:Anormal) O
: O : O
- O - O
@@ -631,12 +635,8 @@ N O
) O ) O
Résultat(s) O Résultat(s) O
récent(s) O récent(s) O
(N O (N:Normal, O
: O A:Anormal) O
Normal, O
A O
: O
Anormal) O
: O : O
- O - O
Groupe O Groupe O
@@ -689,9 +689,7 @@ jeun O
le O le O
04/09/2023 O 04/09/2023 O
à O à O
00 O 00:00 O
: O
00 O
Jeune O Jeune O
pré-opératoire O pré-opératoire O
: O : O
@@ -715,19 +713,18 @@ pré-opératoire O
: O : O
. O . O
[NOM] B-PER GOXOAN B-PER
VISITE O VISITE O
PRE-ANESTHESIQUE O PRE-ANESTHESIQUE O
Date O Date O
: O : O
03/09/2023 O 03/09/2023 O
17 O 17:29 O
: O
29 O
Anesthésiste O Anesthésiste O
: O : O
Dr O Dr O
[NOM] B-PER HANNEQUIN B-PER
Charlène I-PER
VPA O VPA O
/ O / O
Eléments O Eléments O
@@ -755,40 +752,41 @@ Le O
03 O 03 O
Septembre O Septembre O
2023 O 2023 O
17 O 17:32 O
: O
32 O
Page O Page O
: O : O
2/2 O 2/2 O
Anesthésiste O Anesthésiste O
: O : O
Dr O Dr O
[NOM] B-PER LEGRAS B-PER
Claire I-PER
Prémédication O Prémédication O
IPP O I.P.P. O
: O : O
[IPP] B-IPP S1024244 B-IPP
Patient O Patient O
: O : O
[NOM] B-PER PONCABARE B-PER
[NOM] B-PER JEAN I-PER
[DATE_NAISSANCE] B-DATE_NAISSANCE né(e) O
N° O
: O
[DOSSIER] B-NDA
Né(e) O
le O le O
: O : O
[DATE_NAISSANCE] B-DATE_NAISSANCE 17/04/1963 B-DATE_NAISSANCE
N° I-DATE_NAISSANCE
Interv I-DATE_NAISSANCE
: I-DATE_NAISSANCE
23139653 I-DATE_NAISSANCE
Né(e) I-DATE_NAISSANCE
le I-DATE_NAISSANCE
: I-DATE_NAISSANCE
17/04/1963 I-DATE_NAISSANCE
60 O 60 O
ans O ans O
Date O Date O
: O : O
24/08/2023 O 24/08/2023 O
10 O 10:41 O
: O
41 O
Consigne(s) O Consigne(s) O
IDE O IDE O
PREPARATIONS O PREPARATIONS O
@@ -797,9 +795,7 @@ jeun O
le O le O
04/09/2023 O 04/09/2023 O
à O à O
00 O 00:00 O
: O
00 O
Jeune O Jeune O
pré-opératoire O pré-opératoire O
: O : O
@@ -882,15 +878,11 @@ J-1 O
indapamide O indapamide O
2.5mg O 2.5mg O
CP, O CP, O
Matin O Matin:1 O
: O
1 O
perindopril O perindopril O
10mg O 10mg O
CP, O CP, O
Matin O Matin:1 O
: O
1 O
Date O Date O
/ O / O
Heure O Heure O
@@ -901,9 +893,7 @@ Le O
03 O 03 O
Septembre O Septembre O
2023 O 2023 O
17 O 17:32 O
: O
32 O
Page O Page O
: O : O
1/1 O 1/1 O

View File

@@ -28,55 +28,52 @@ S O
Q O Q O
U O U O
E O E O
[MASK] O 640780417 B-HOPITAL
* O *640780417* I-HOPITAL
[MASK] O
* O
Praticiens O Praticiens O
Hospitaliers O Hospitaliers O
: O : O
Dr O Dr O
T. O T. O
[NOM] B-PER GRELLETY B-PER
Oncologie O Oncologie O
médicale O médicale O
Dr O Dr O
F. O F. O
[NOM] B-PER MINNE B-PER
Oncologie O Oncologie O
médicale O médicale O
Dr O Dr O
S. O S. O
[NOM] B-PER GHECK B-PER
Chirurgie O Chirurgie O
Sénologie- O Sénologie- O
Gynécologie O Gynécologie O
Dr O Dr O
L. O L. O
[NOM] B-PER BOURDARIAS B-PER
Chirurgie O Chirurgie O
Sénologie- O Sénologie- O
Gynécologie O Gynécologie O
Dr O Dr O
B. O B. O
[NOM] B-PER GOLHEN B-PER
Radiologie O Radiologie O
Dr O Dr O
A. O A. O
[NOM] B-PER CHARRIE B-PER
Radiologie O Radiologie O
Dr O Dr O
C. O C. O
[NOM] B-PER MAUREL B-PER
Radiologie O Radiologie O
Dr O Dr O
S. O S.GIRAUD O
[NOM] B-PER
Médecin O Médecin O
généticien O généticien O
Mme O Mme O
A. O A. O
[NOM] B-PER DENISE B-PER
Conseillère O Conseillère O
en O en O
génétique O génétique O
@@ -86,14 +83,14 @@ Service O
: O : O
Mme O Mme O
C. O C. O
[NOM] B-PER MONNIER B-PER
 O  O
[TEL] B-TEL 05.59.44.33.02 B-TEL
Mr O Mr O
L. O L. O
[NOM] B-PER DAVID B-PER
 O  O
[TEL] B-TEL 05.59.44.37.73 B-TEL
Secrétariat O Secrétariat O
Médical O Médical O
: O : O
@@ -101,39 +98,43 @@ Accueil, O
Rendez-vous O Rendez-vous O
Mme O Mme O
C. O C. O
[NOM] B-PER SARRATIA B-PER
Mme O Mme O
A. O A. O
[NOM] B-PER BOUNEY B-PER
 O  O
[TEL] B-TEL 05.33.78.81.90 B-TEL
[EMAIL] B-EMAIL secr.hms@ch-cotebasque.fr B-EMAIL
 O  O
[ADRESSE] B-ADRESSE 13 B-PER
Interne O avenue I-PER
[NOM] B-PER de I-PER
[NOM] B-PER lInterne I-PER
Jacques I-PER
Loëb I-PER
- O - O
B.P. O B.P. O
8 O 8 O
O O
[CODE_POSTAL] B-ZIP 64109 B-ZIP
[MASK] O BAYONNE I-ZIP
Cedex I-ZIP
Pôle B-HOPITAL
Spécialités I-HOPITAL
Médicales I-HOPITAL
(Chef O (Chef O
de O de O
[MASK] O Pôle O
. O Dr O
E.ELLIE) O
[NOM] B-PER
) O
 O  O
Secrétariat O Secrétariat O
: O : O
[TEL] B-TEL 05.33.78.81.90 B-TEL
Télécopie O Télécopie O
: O : O
[TEL] B-TEL 05.59.44.33.62 B-TEL
[EMAIL] B-EMAIL secr.hms@ch-cotebasque.fr B-EMAIL
CL O CL O
Bayonne, O Bayonne, O
le O le O
@@ -141,28 +142,60 @@ le O
Juin O Juin O
2023 O 2023 O
Docteur O Docteur O
[NOM] B-PER Marie-Alix B-PER
[MASK] O GREGOIRE I-PER
[ADRESSE] B-ADRESSE POLYCLINIQUE I-PER
[CODE_POSTAL] B-ZIP CÔTE I-PER
[CODE_POSTAL] B-ZIP BASQUE I-PER
SUD I-PER
7, B-HOPITAL
RUE I-HOPITAL
LÉONCE I-HOPITAL
GOYETCHE I-HOPITAL
- I-HOPITAL
CS I-HOPITAL
30149 B-ZIP
64501 I-ZIP
ST I-ZIP
JEAN I-ZIP
DE I-ZIP
LUZ I-ZIP
CEDEX I-ZIP
Doubles O Doubles O
aux O aux O
: O : O
Docteur O Docteur O
[NOM] B-PER Jean-Jacques B-PER
BENICHOU I-PER
Cabinet O Cabinet O
Médical O Médical O
[NOM] B-PER Aice B-PER
Egoa O Egoa O
[ADRESSE] B-ADRESSE Place B-ADRESSE
[CODE_POSTAL] B-ZIP du I-ADRESSE
Fronton B-ZIP
64500 I-ZIP
CIBOURE I-ZIP
Docteur O Docteur O
[NOM] B-PER Oliver B-PER
[NOM] B-PER JENKINS I-PER
[ADRESSE] B-ADRESSE POLYCLINIQUE I-PER
[CODE_POSTAL] B-ZIP CÔTE I-PER
[CODE_POSTAL] B-ZIP BASQUE I-PER
SUD I-PER
7, I-PER
RUE I-PER
LÉONCE I-PER
GOYETCHE I-PER
- I-PER
CS I-PER
30149 B-ZIP
64501 I-ZIP
ST I-ZIP
JEAN I-ZIP
DE I-ZIP
LUZ I-ZIP
CEDEX I-ZIP
Chers O Chers O
Confrères, O Confrères, O
Nous O Nous O
@@ -179,20 +212,22 @@ Sénologie-gynécologie O
le O le O
02/06/2023, O 02/06/2023, O
Madame O Madame O
[NOM] B-PER Nicole O
, O CLAVEL, O
[DATE_NAISSANCE] B-DATE_NAISSANCE née O
. O le O
25/08/1942. O
Veuillez O Veuillez O
trouver O trouver O
ci-joint O ci-joint O
le O le O
compte-rendu. O compte-rendu. O
Docteur O Docteur O
[NOM] B-PER Sophie B-PER
GHECK I-PER
Docteur O Docteur O
[NOM] B-PER Floriane B-PER
MINNE I-PER
Courrier O Courrier O
relu O relu O
et O et O
@@ -200,11 +235,15 @@ validé O
par O par O
les O les O
médecins O médecins O
[ETABLISSEMENT] O Hôpital B-PER
[NOM] B-PER de I-PER
[NOM] B-PER Jour I-PER
, O Multidisciplinaire I-PER
[DATE_NAISSANCE] B-DATE_NAISSANCE de B-DATE_NAISSANCE
Sénologie-Gynécologie I-DATE_NAISSANCE
CLAVEL I-DATE_NAISSANCE
NICOLE, I-DATE_NAISSANCE
25/08/1942 I-DATE_NAISSANCE
COMPTE-RENDU O COMPTE-RENDU O
DE O DE O
VISITE O VISITE O
@@ -218,27 +257,30 @@ Vue O
par O par O
: O : O
Docteurs O Docteurs O
[NOM] B-PER GHECK, B-PER
, O MINNE I-PER
[NOM] B-PER
ainsi O ainsi O
que O que O
Madame O Madame O
[NOM] B-PER ITHURBIDE, O
, O
IPA O IPA O
Adressée O Adressée O
par O par O
: O : O
Docteur O Docteur O
[NOM] B-PER GREGOIRE B-PER
du O du O
court O court O
séjour O séjour O
gériatrie O gériatrie O
à O à O
la O la O
[ETABLISSEMENT] O Polyclinique O
de O
Saint O
Jean O
de O
Luz O
où O où O
est O est O
actuellement O actuellement O
@@ -462,7 +504,10 @@ DE O
PRISE O PRISE O
EN O EN O
CHARGE O CHARGE O
[AGE] B-AGE Patiente B-AGE
de I-AGE
80 I-AGE
ans I-AGE
vue O vue O
pour O pour O
probable O probable O
@@ -540,10 +585,9 @@ symptomatique O
est O est O
à O à O
envisager. O envisager. O
[NOM] B-PER CLAVEL B-PER
[NOM] B-PER NICOLE, B-DATE_NAISSANCE
, O 25/08/1942 I-DATE_NAISSANCE
[DATE_NAISSANCE] B-DATE_NAISSANCE
Questionnaire O Questionnaire O
Qualité O Qualité O
de O de O
@@ -589,9 +633,11 @@ disponible O
si O si O
nécessité. O nécessité. O
Docteur O Docteur O
[NOM] B-PER Sophie B-PER
GHECK I-PER
Docteur O Docteur O
[NOM] B-PER Floriane B-PER
MINNE I-PER
Courrier O Courrier O
relu O relu O
et O et O

View File

@@ -1,9 +1,8 @@
CROp O CROp O
[NOM] B-PER Epi B-PER
- O - O
[NOM] B-PER COSSU, B-PER
, O REMI I-PER
[NOM] B-PER
_______________________________________________________________________________________________________________ O _______________________________________________________________________________________________________________ O
Compte O Compte O
rendu O rendu O
@@ -12,16 +11,14 @@ opératoire O
neurochirurgie O neurochirurgie O
type O type O
22/08/23 O 22/08/23 O
14 O 14:31 O
: O
31 O
(mod. O (mod. O
le O le O
22/08/23 O 22/08/23 O
14:58 O 14:58 O
par O par O
[NOM] B-PER ARTIGUEBIEILLE B-PER
[NOM] B-PER Veronique I-PER
, O , O
statut O statut O
Réf O Réf O
@@ -31,16 +28,22 @@ Bayonne, O
le O le O
22/08/2023 O 22/08/2023 O
Dr O Dr O
[NOM] B-PER Maria B-PER
BISCAY-SALLABERRY I-PER
CABINET O CABINET O
[NOM] B-PER ETXEBARNONDOA B-PER
Le O Le O
BOURG O BOURG O
[CODE_POSTAL] B-ZIP 64780 B-ZIP
IRISSARRY I-ZIP
Mr O Mr O
[NOM] B-PER REMI B-PER
[ADRESSE] B-ADRESSE COSSU I-PER
[CODE_POSTAL] B-ZIP 200 B-ADRESSE
CHEMIN I-ADRESSE
SORHABIETA B-ZIP
64640 I-ZIP
IHOLDY I-ZIP
Madame O Madame O
et O et O
cher O cher O
@@ -62,9 +65,7 @@ patient, O
Mr O Mr O
R O R O
le O le O
[DATE_NAISSANCE] B-DATE_NAISSANCE 07/08/1999. O
. O
En O En O
vous O vous O
remerciant O remerciant O
@@ -88,7 +89,8 @@ sentiments O
confraternellement O confraternellement O
dé O dé O
Docteur O Docteur O
[NOM] B-PER Joe B-PER
FADDOUL I-PER
Courrier O Courrier O
lu O lu O
et O et O
@@ -102,34 +104,38 @@ OPÉRATOIRE O
Date O Date O
: O : O
22/08/2023 O 22/08/2023 O
[DOSSIER] B-NDA Dossier O
: O
23159905 O
Nom O Nom O
: O : O
[NOM] B-PER COSSU B-PER
Prénom O Prénom O
: O : O
[NOM] B-PER REMI B-PER
Date O Date O
de O de O
naissance O naissance O
: O : O
[DATE_NAISSANCE] B-DATE_NAISSANCE 07/08/1999 B-DATE_NAISSANCE
Service O Service O
: O : O
Neurochirurgie O Neurochirurgie O
CHIRURGIEN O CHIRURGIEN O
: O : O
Dr O Dr O
[NOM] B-PER FADDOUL B-PER
Joe I-PER
AIDE O AIDE O
OPERATOIRE O OPERATOIRE O
: O : O
[NOM] B-PER STEFANINI B-PER
[NOM] B-PER Andréa I-PER
ANESTHÉSISTE O ANESTHÉSISTE O
: O : O
Dr O Dr O
[NOM] B-PER CUCUPHAT B-PER
Pierre-Lou I-PER
INTERVENTION O INTERVENTION O
PRATIQUÉE O PRATIQUÉE O
: O : O
@@ -149,10 +155,11 @@ LA O
MALADIE O MALADIE O
: O : O
Mr O Mr O
[NOM] B-PER COSSU O
, O Rémi, O
[DATE_NAISSANCE] B-DATE_NAISSANCE né O
, O le O
07/08/1999, O
qui O qui O
est O est O
connu O connu O
@@ -171,15 +178,12 @@ patient O
Page O Page O
1 O 1 O
18/04/2025 O 18/04/2025 O
11 O 11:54:37 O
: O
54:37 O
CROp O CROp O
[NOM] B-PER Epi B-PER
- O - O
[NOM] B-PER COSSU, B-PER
, O REMI I-PER
[NOM] B-PER
_______________________________________________________________________________________________________________ O _______________________________________________________________________________________________________________ O
Compte O Compte O
rendu O rendu O
@@ -206,11 +210,11 @@ complication O
particulière O particulière O
et O et O
Mr O Mr O
[NOM] B-PER COSSU B-PER
était O était O
hospitalisé O hospitalisé O
à O à O
[NOM] B-PER MARIENIA B-PER
depui O depui O
pour O pour O
réaliser O réaliser O
@@ -243,12 +247,11 @@ nos O
collègues O collègues O
MPR, O MPR, O
Dr O Dr O
[NOM] B-PER BEGUE B-PER
à O à O
[NOM] B-PER MARIENIA, O
, O
Mr O Mr O
[NOM] B-PER COSSU B-PER
a O a O
été O été O
transféré O transféré O
@@ -293,7 +296,7 @@ bien O
expliqués O expliqués O
à O à O
Mr O Mr O
[NOM] B-PER COSSU B-PER
qu O qu O
geste O geste O
chirurgical. O chirurgical. O
@@ -482,7 +485,8 @@ négligeable, O
non O non O
compensée O compensée O
Docteur O Docteur O
[NOM] B-PER Joe B-PER
FADDOUL I-PER
Courrier O Courrier O
lu O lu O
et O et O
@@ -496,6 +500,4 @@ patient O
Page O Page O
2 O 2 O
18/04/2025 O 18/04/2025 O
11 O 11:54:37 O
: O
54:37 O

View File

@@ -1,9 +1,8 @@
CROp O CROp O
[NOM] B-PER Epi B-PER
- O - O
[NOM] B-PER DEAUX, B-PER
, O JEAN I-PER
[NOM] B-PER
_______________________________________________________________________________________________________________ O _______________________________________________________________________________________________________________ O
Compte O Compte O
rendu O rendu O
@@ -14,16 +13,14 @@ type O
chirurgie O chirurgie O
viscérale O viscérale O
13/09/23 O 13/09/23 O
14 O 14:55 O
: O
55 O
(mod. O (mod. O
le O le O
13/09/23 O 13/09/23 O
15:05 O 15:05 O
par O par O
[NOM] B-PER LEVERGE B-PER
[NOM] B-PER Jessica I-PER
, O , O
statut O statut O
: O : O
@@ -34,22 +31,36 @@ Bayonne, O
le O le O
13/09/2023 O 13/09/2023 O
Docteur O Docteur O
[NOM] B-PER Martine B-PER
[ADRESSE] B-ADRESSE GOMEZ I-PER
[CODE_POSTAL] B-ZIP 10 B-ADRESSE
rue I-ADRESSE
des B-ZIP
augustins I-ZIP
64 I-ZIP
100 I-ZIP
BAYONNE O BAYONNE O
Monsieur O Monsieur O
[NOM] B-PER JEAN B-PER
[ADRESSE] B-ADRESSE DEAUX I-PER
[CODE_POSTAL] B-ZIP 36 B-ADRESSE
RUE I-ADRESSE
VICTOR B-ZIP
HUGO I-ZIP
64100 I-ZIP
BAYONNE I-ZIP
Docteur O Docteur O
[NOM] B-PER Tam B-PER
KHUONG I-PER
Gastro O Gastro O
entérologie O entérologie O
[MASK] O CHCB B-HOPITAL
Monsieur O Monsieur O
[NOM] B-PER JEAN B-PER
[DATE_NAISSANCE] B-DATE_NAISSANCE DEAUX I-PER
Né B-DATE_NAISSANCE
le I-DATE_NAISSANCE
14/04/1953 I-DATE_NAISSANCE
RESECTION O RESECTION O
SEGMENTAIRE O SEGMENTAIRE O
DE O DE O
@@ -69,11 +80,11 @@ Opérateur O
: O : O
Docteur O Docteur O
R. O R. O
[NOM] B-PER GONTIER B-PER
Anesthésiste(s) O Anesthésiste(s) O
Docteur O Docteur O
E. O E. O
[NOM] B-PER DUFOUR B-PER
Aide(s) O Aide(s) O
: O : O
L'interne O L'interne O
@@ -285,15 +296,12 @@ patient O
Page O Page O
1 O 1 O
22/04/2025 O 22/04/2025 O
10 O 10:07:08 O
: O
07:08 O
CROp O CROp O
[NOM] B-PER Epi B-PER
- O - O
[NOM] B-PER DEAUX, B-PER
, O JEAN I-PER
[NOM] B-PER
_______________________________________________________________________________________________________________ O _______________________________________________________________________________________________________________ O
Compte O Compte O
rendu O rendu O
@@ -333,6 +341,4 @@ patient O
Page O Page O
2 O 2 O
22/04/2025 O 22/04/2025 O
10 O 10:07:08 O
: O
07:08 O

View File

@@ -2,7 +2,7 @@ Courrier O
Epi O Epi O
- O - O
RICHARD, O RICHARD, O
[NOM] B-PER CLAUDE B-PER
___________________________________________________________________________________________________________________________ O ___________________________________________________________________________________________________________________________ O
Courriers O Courriers O
médicaux O médicaux O
@@ -11,16 +11,14 @@ Lettre O
de O de O
sortie O sortie O
05/07/23 O 05/07/23 O
14 O 14:17 O
: O
17 O
(mod. O (mod. O
le O le O
07/07/23 O 07/07/23 O
12:19 O 12:19 O
par O par O
[NOM] B-PER PENOUILH B-PER
[NOM] B-PER Emilie I-PER
, O , O
statut O statut O
: O : O
@@ -34,7 +32,8 @@ le O
juillet O juillet O
2023 O 2023 O
Docteur O Docteur O
[NOM] B-PER Philippe B-PER
ETCHETO I-PER
Centre O Centre O
Médical O Médical O
de O de O
@@ -43,14 +42,16 @@ Zup O
Quartier O Quartier O
Ste O Ste O
Croix O Croix O
[CODE_POSTAL] B-ZIP 64100 B-ZIP
BAYONNE I-ZIP
Cher O Cher O
Confrère, O Confrère, O
Monsieur O Monsieur O
[NOM] B-PER Claude O
, O RICHARD, O
[DATE_NAISSANCE] B-DATE_NAISSANCE né O
, O le O
27/08/1954, O
a O a O
été O été O
hospitalisé O hospitalisé O
@@ -409,21 +410,20 @@ patient O
Page O Page O
1 O 1 O
17/04/2025 O 17/04/2025 O
09 O 09:17:42 O
: O
17:42 O
Courrier O Courrier O
Epi O Epi O
- O - O
RICHARD, O RICHARD, O
[NOM] B-PER CLAUDE B-PER
___________________________________________________________________________________________________________________________ O ___________________________________________________________________________________________________________________________ O
Courriers O Courriers O
médicaux O médicaux O
Bien O Bien O
confraternellement. O confraternellement. O
Docteur O Docteur O
[NOM] B-PER Antoine B-PER
DOUARD I-PER
Courrier O Courrier O
lu O lu O
et O et O
@@ -437,6 +437,4 @@ patient O
Page O Page O
2 O 2 O
17/04/2025 O 17/04/2025 O
09 O 09:17:42 O
: O
17:42 O

View File

@@ -1,9 +1,10 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
""" """
Export silver annotations — Génère des données d'entraînement BIO à partir du pipeline existant. Export silver annotations — BIO via alignement texte original ↔ pseudonymisé.
================================================================================================ =============================================================================
Utilise le pipeline regex+NER+VLM actuel pour produire des annotations "silver standard" Aligne le texte extrait du PDF original avec le texte pseudonymisé (.pseudonymise.txt)
sur les 706 OGC. Ces annotations servent de base pour fine-tuner CamemBERT-bio. pour créer des annotations BIO fiables. Les placeholders [NOM], [TEL], etc. dans le
texte pseudonymisé indiquent exactement quels tokens ont été masqués.
Usage: Usage:
python scripts/export_silver_annotations.py [--limit N] [--out-dir DIR] python scripts/export_silver_annotations.py [--limit N] [--out-dir DIR]
@@ -13,21 +14,15 @@ Format BIO: TOKEN\tLABEL (un token par ligne, lignes vides entre phrases)
""" """
import sys import sys
import re import re
import json import difflib
import argparse import argparse
from pathlib import Path from pathlib import Path
from typing import List, Tuple from typing import Dict, List, Tuple
sys.path.insert(0, str(Path(__file__).parent.parent)) sys.path.insert(0, str(Path(__file__).parent.parent))
# Regex pour détecter les placeholders et reconstruire l'alignement
PLACEHOLDER_RE = re.compile(
r"\[(NOM|TEL|EMAIL|NIR|IPP|DOSSIER|NDA|EPISODE|RPPS|DATE_NAISSANCE|"
r"ADRESSE|CODE_POSTAL|VILLE|MASK|FINESS|OGC|AGE|ETAB|IBAN)\]"
)
# Mapping placeholder → label BIO # Mapping placeholder → label BIO
PH_TO_BIO = { PLACEHOLDER_TO_BIO: Dict[str, str] = {
"NOM": "PER", "NOM": "PER",
"TEL": "TEL", "TEL": "TEL",
"EMAIL": "EMAIL", "EMAIL": "EMAIL",
@@ -41,78 +36,178 @@ PH_TO_BIO = {
"ADRESSE": "ADRESSE", "ADRESSE": "ADRESSE",
"CODE_POSTAL": "ZIP", "CODE_POSTAL": "ZIP",
"VILLE": "VILLE", "VILLE": "VILLE",
"ETAB": "HOPITAL", "HOPITAL": "HOPITAL",
"FINESS": "HOPITAL", "MASK": "HOPITAL", # [MASK] = hôpital masqué par force_regex
"IBAN": "IBAN", "IBAN": "IBAN",
"AGE": "AGE", "AGE": "AGE",
"OGC": "NDA",
"MASK": "O", # MASK générique = pas d'annotation spécifique
} }
RE_PLACEHOLDER = re.compile(r"^\[([A-Z_]+)\]$")
def text_to_bio(pseudonymised_text: str) -> List[Tuple[str, str]]: SRC = Path("/home/dom/Téléchargements/II-1 Ctrl_T2A_2025_CHCB_DocJustificatifs (1)")
"""Convertit un texte pseudonymisé en séquence BIO. AUDIT_DIR = SRC / "anonymise_audit_30"
Les tokens [PLACEHOLDER] deviennent B-TYPE / I-TYPE.
Les tokens normaux deviennent O. def extract_original_text(pdf_path: Path) -> str:
"""Extrait le texte brut d'un PDF (même méthode que le pipeline)."""
import anonymizer_core_refactored_onnx as core
pages_text, _, _, _ = core.extract_text_with_fallback_ocr(pdf_path)
return "\f".join(pages_text)
def tokenize_text(text: str) -> List[str]:
"""Split en tokens whitespace, en nettoyant les caractères de contrôle."""
# Remplacer \f et \r par \n pour l'alignement
text = text.replace("\f", "\n").replace("\r", "")
tokens = []
for line in text.split("\n"):
line_toks = line.split()
if line_toks:
tokens.extend(line_toks)
return tokens
def align_and_annotate(original_text: str, pseudo_text: str) -> List[Tuple[str, str]]:
"""Aligne texte original et pseudonymisé pour créer les annotations BIO.
Utilise SequenceMatcher pour trouver les différences.
Quand le pseudo contient [PLACEHOLDER], les tokens originaux correspondants
reçoivent le label BIO approprié.
""" """
orig_tokens = tokenize_text(original_text)
pseudo_tokens = tokenize_text(pseudo_text)
# Normaliser pour l'alignement (lowercase, sans accents pour meilleur matching)
def normalize(tok):
return tok.lower().strip(".,;:!?()[]{}\"'")
orig_norm = [normalize(t) for t in orig_tokens]
pseudo_norm = [normalize(t) for t in pseudo_tokens]
sm = difflib.SequenceMatcher(None, orig_norm, pseudo_norm, autojunk=False)
opcodes = sm.get_opcodes()
bio_tokens: List[Tuple[str, str]] = [] bio_tokens: List[Tuple[str, str]] = []
# Split le texte en segments : alternance texte normal / placeholder for tag, i1, i2, j1, j2 in opcodes:
parts = PLACEHOLDER_RE.split(pseudonymised_text) if tag == "equal":
# parts = [texte, label, texte, label, texte, ...] # Tokens identiques → O
for t in orig_tokens[i1:i2]:
bio_tokens.append((t, "O"))
i = 0 elif tag == "replace":
while i < len(parts): # Analyser le côté pseudo : quels tokens sont des placeholders ?
if i % 2 == 0: pseudo_chunk = pseudo_tokens[j1:j2]
# Texte normal placeholder_labels = [] # (index_in_pseudo, bio_label) pour chaque placeholder
text_part = parts[i] non_placeholder_norms = set()
for word in text_part.split(): for pi, pt in enumerate(pseudo_chunk):
word = word.strip() m = RE_PLACEHOLDER.match(pt)
if word: if m:
bio_tokens.append((word, "O")) bio_label = PLACEHOLDER_TO_BIO.get(m.group(1))
if bio_label:
placeholder_labels.append((pi, bio_label))
else: else:
# Label de placeholder non_placeholder_norms.add(normalize(pt))
label = parts[i]
bio_label = PH_TO_BIO.get(label, "O") if not placeholder_labels:
if bio_label != "O": # Pas de placeholder → O
# Le placeholder remplace un ou plusieurs tokens for t in orig_tokens[i1:i2]:
bio_tokens.append((f"[{label}]", f"B-{bio_label}")) bio_tokens.append((t, "O"))
elif len(placeholder_labels) == 1:
# Un seul placeholder : tous les tokens originaux (sauf ceux
# qui matchent un token non-placeholder du pseudo) prennent ce label
label = placeholder_labels[0][1]
first = True
for t in orig_tokens[i1:i2]:
if normalize(t) in non_placeholder_norms:
bio_tokens.append((t, "O"))
first = True
else: else:
bio_tokens.append((f"[{label}]", "O")) prefix = "B-" if first else "I-"
i += 1 bio_tokens.append((t, f"{prefix}{label}"))
first = False
else:
# Plusieurs placeholders : distribuer les tokens originaux
# Stratégie : répartir proportionnellement, chaque groupe commence par B-
n_orig = i2 - i1
n_placeholders = len(placeholder_labels)
# Exclure d'abord les tokens qui matchent des non-placeholders
orig_assignments = []
for t in orig_tokens[i1:i2]:
if normalize(t) in non_placeholder_norms:
orig_assignments.append(("O", None))
else:
orig_assignments.append(("PII", None))
# Distribuer les tokens PII entre les placeholders
pii_indices = [k for k, (tp, _) in enumerate(orig_assignments) if tp == "PII"]
n_pii = len(pii_indices)
if n_pii > 0 and n_placeholders > 0:
chunk_size = max(1, n_pii // n_placeholders)
for pi_idx, (_, label) in enumerate(placeholder_labels):
start_pii = pi_idx * chunk_size
end_pii = (pi_idx + 1) * chunk_size if pi_idx < n_placeholders - 1 else n_pii
for k in range(start_pii, min(end_pii, n_pii)):
orig_assignments[pii_indices[k]] = ("PII", label)
# Générer les BIO tokens
prev_label = None
for k, (t, (tp, label)) in enumerate(zip(orig_tokens[i1:i2], orig_assignments)):
if tp == "O" or label is None:
bio_tokens.append((t, "O"))
prev_label = None
else:
prefix = "B-" if label != prev_label else "I-"
bio_tokens.append((t, f"{prefix}{label}"))
prev_label = label
elif tag == "delete":
# Tokens présents uniquement dans l'original → O
for t in orig_tokens[i1:i2]:
bio_tokens.append((t, "O"))
elif tag == "insert":
# Tokens ajoutés dans le pseudo (rare) → ignorer
pass
return bio_tokens return bio_tokens
def export_document(pseudo_path: Path, out_dir: Path) -> int: def export_document(pdf_path: Path, pseudo_path: Path, out_dir: Path) -> Tuple[int, int]:
"""Exporte un fichier pseudonymisé en format BIO. Retourne le nombre de tokens.""" """Exporte un document en format BIO. Retourne (nb_tokens, nb_entités)."""
text = pseudo_path.read_text(encoding="utf-8", errors="replace") # Extraire le texte original
original_text = extract_original_text(pdf_path)
if not original_text.strip():
return 0, 0
bio_tokens = text_to_bio(text) # Lire le texte pseudonymisé
if not bio_tokens: pseudo_text = pseudo_path.read_text(encoding="utf-8")
return 0 if not pseudo_text.strip():
return 0, 0
# Écrire en format CoNLL (TOKEN\tLABEL) # Aligner et annoter
out_path = out_dir / pseudo_path.name.replace(".pseudonymise.txt", ".bio") bio_tokens = align_and_annotate(original_text, pseudo_text)
# Écrire en format CoNLL
out_name = pdf_path.stem + ".bio"
out_path = out_dir / out_name
lines = [] lines = []
for token, label in bio_tokens: for token, label in bio_tokens:
# Séparer les "phrases" par des lignes vides (heuristique: point final ou retour ligne) # Séparer les phrases par des lignes vides (ponctuation finale)
if token in (".", "!", "?") and label == "O": if token in (".", "!", "?") and label == "O":
lines.append(f"{token}\t{label}") lines.append(f"{token}\t{label}")
lines.append("") # séparateur de phrase lines.append("")
else: else:
lines.append(f"{token}\t{label}") lines.append(f"{token}\t{label}")
out_path.write_text("\n".join(lines), encoding="utf-8") out_path.write_text("\n".join(lines), encoding="utf-8")
return len(bio_tokens)
n_ents = sum(1 for _, l in bio_tokens if l.startswith("B-"))
return len(bio_tokens), n_ents
def main(): def main():
parser = argparse.ArgumentParser(description="Export silver annotations BIO") parser = argparse.ArgumentParser(description="Export silver annotations BIO (alignement original ↔ pseudo)")
parser.add_argument("--input-dir", type=Path,
default=Path("/home/dom/Téléchargements/II-1 Ctrl_T2A_2025_CHCB_DocJustificatifs (1)/anonymise_audit_30"),
help="Répertoire contenant les .pseudonymise.txt")
parser.add_argument("--out-dir", type=Path, parser.add_argument("--out-dir", type=Path,
default=Path(__file__).parent.parent / "data" / "silver_annotations", default=Path(__file__).parent.parent / "data" / "silver_annotations",
help="Répertoire de sortie") help="Répertoire de sortie")
@@ -121,23 +216,34 @@ def main():
args.out_dir.mkdir(parents=True, exist_ok=True) args.out_dir.mkdir(parents=True, exist_ok=True)
pseudo_files = sorted(args.input_dir.glob("*.pseudonymise.txt")) # Trouver les paires PDF + pseudo
if args.limit > 0: pseudo_files = sorted(AUDIT_DIR.glob("*.pseudonymise.txt"))
pseudo_files = pseudo_files[:args.limit] pairs = []
for pseudo_path in pseudo_files:
# Retrouver le PDF source
base_name = pseudo_path.name.replace(".pseudonymise.txt", ".pdf")
# Chercher dans les sous-dossiers OGC
found = list(SRC.glob(f"*/{base_name}"))
if found:
pairs.append((found[0], pseudo_path))
print(f"Export silver annotations: {len(pseudo_files)} fichiers → {args.out_dir}") if args.limit > 0:
pairs = pairs[:args.limit]
print(f"Export silver annotations: {len(pairs)} documents → {args.out_dir}")
total_tokens = 0 total_tokens = 0
total_entities = 0 total_entities = 0
for f in pseudo_files: for pdf_path, pseudo_path in pairs:
n = export_document(f, args.out_dir) try:
ent_count = sum(1 for line in (args.out_dir / f.name.replace(".pseudonymise.txt", ".bio")).read_text().splitlines() n_tok, n_ent = export_document(pdf_path, pseudo_path, args.out_dir)
if line and not line.endswith("\tO")) total_tokens += n_tok
total_tokens += n total_entities += n_ent
total_entities += ent_count print(f" {pdf_path.name}: {n_tok} tokens, {n_ent} entités")
print(f" {f.name}: {n} tokens, {ent_count} entités") except Exception as e:
print(f" {pdf_path.name}: ERREUR {e}")
print(f"\nTotal: {total_tokens} tokens, {total_entities} entités annotées") print(f"\nTotal: {total_tokens} tokens, {total_entities} entités B-")
print(f"Sortie: {args.out_dir}") print(f"Sortie: {args.out_dir}")

View File

@@ -15,8 +15,11 @@ import sys
import argparse import argparse
from pathlib import Path from pathlib import Path
from typing import Dict, List from typing import Dict, List
from collections import Counter
import numpy as np import numpy as np
import torch
from torch import nn
# Vérifier les dépendances # Vérifier les dépendances
try: try:
@@ -59,38 +62,60 @@ ID2LABEL = {i: l for l, i in LABEL2ID.items()}
MODEL_NAME = "almanach/camembert-bio-base" MODEL_NAME = "almanach/camembert-bio-base"
def load_bio_files(data_dir: Path) -> Dict[str, List]: def load_bio_files(data_dir: Path, window_size: int = 200, stride: int = 100) -> Dict[str, List]:
"""Charge les fichiers .bio en format HuggingFace datasets.""" """Charge les fichiers .bio et découpe en fenêtres glissantes.
Les documents cliniques sont très longs. On les découpe en fenêtres de
~window_size tokens avec un chevauchement de stride. On ne garde que les
fenêtres contenant au moins une entité (pour l'équilibre des classes).
"""
tokens_list: List[List[str]] = [] tokens_list: List[List[str]] = []
labels_list: List[List[int]] = [] labels_list: List[List[int]] = []
for bio_file in sorted(data_dir.glob("*.bio")): for bio_file in sorted(data_dir.glob("*.bio")):
text = bio_file.read_text(encoding="utf-8") text = bio_file.read_text(encoding="utf-8")
current_tokens: List[str] = [] # Charger tous les tokens du document
current_labels: List[int] = [] all_tokens: List[str] = []
all_labels: List[int] = []
for line in text.splitlines(): for line in text.splitlines():
line = line.strip() line = line.strip()
if not line: if not line:
# Fin de phrase
if current_tokens:
tokens_list.append(current_tokens)
labels_list.append(current_labels)
current_tokens = []
current_labels = []
continue continue
parts = line.split("\t") parts = line.split("\t")
if len(parts) != 2: if len(parts) != 2:
continue continue
token, label = parts token, label = parts
label_id = LABEL2ID.get(label, LABEL2ID["O"]) label_id = LABEL2ID.get(label, LABEL2ID["O"])
current_tokens.append(token) all_tokens.append(token)
current_labels.append(label_id) all_labels.append(label_id)
if current_tokens: if not all_tokens:
tokens_list.append(current_tokens) continue
labels_list.append(current_labels)
# Découper en fenêtres glissantes
n = len(all_tokens)
for start in range(0, n, stride):
end = min(start + window_size, n)
chunk_tokens = all_tokens[start:end]
chunk_labels = all_labels[start:end]
# Corriger les I- en début de fenêtre → B-
if chunk_labels and chunk_labels[0] > 0:
lbl_name = LABEL_LIST[chunk_labels[0]]
if lbl_name.startswith("I-"):
b_name = "B-" + lbl_name[2:]
if b_name in LABEL2ID:
chunk_labels[0] = LABEL2ID[b_name]
# Garder les fenêtres avec entités + quelques fenêtres "O" (10%)
has_entities = any(l != 0 for l in chunk_labels)
if has_entities or (start % (stride * 10) == 0):
tokens_list.append(chunk_tokens)
labels_list.append(chunk_labels)
if end >= n:
break
return {"tokens": tokens_list, "ner_tags": labels_list} return {"tokens": tokens_list, "ner_tags": labels_list}
@@ -131,6 +156,59 @@ def tokenize_and_align(examples, tokenizer):
return tokenized return tokenized
class WeightedNERTrainer(Trainer):
"""Trainer avec poids de classe pour contrer le déséquilibre O vs entités."""
def __init__(self, class_weights=None, **kwargs):
super().__init__(**kwargs)
if class_weights is not None:
self.class_weights = class_weights.to(self.args.device)
else:
self.class_weights = None
def compute_loss(self, model, inputs, return_outputs=False, **kwargs):
labels = inputs.pop("labels")
outputs = model(**inputs)
logits = outputs.logits
if self.class_weights is not None:
loss_fct = nn.CrossEntropyLoss(
weight=self.class_weights,
ignore_index=-100,
label_smoothing=0.1,
)
else:
loss_fct = nn.CrossEntropyLoss(ignore_index=-100, label_smoothing=0.1)
loss = loss_fct(logits.view(-1, self.model.config.num_labels), labels.view(-1))
return (loss, outputs) if return_outputs else loss
def compute_class_weights(raw_data: Dict, num_labels: int, max_weight: float = 10.0) -> torch.FloatTensor:
"""Calcule les poids inversement proportionnels à la fréquence, cappés après normalisation."""
counts = Counter()
for labels in raw_data["ner_tags"]:
for l in labels:
counts[l] += 1
total = sum(counts.values())
weights = torch.ones(num_labels)
for label_id, count in counts.items():
if count > 0:
weights[label_id] = total / (num_labels * count)
# Normaliser : O=1.0
if weights[0] > 0:
scale = 1.0 / weights[0]
weights *= scale
# Capper APRÈS normalisation pour limiter le déséquilibre
weights = torch.clamp(weights, max=max_weight)
print(f" Class weights (O={weights[0]:.1f}, non-O moyen={weights[1:].mean():.1f}, max={weights[1:].max():.1f})")
return weights
def main(): def main():
parser = argparse.ArgumentParser(description="Fine-tune CamemBERT-bio pour désidentification") parser = argparse.ArgumentParser(description="Fine-tune CamemBERT-bio pour désidentification")
parser.add_argument("--data-dir", type=Path, parser.add_argument("--data-dir", type=Path,
@@ -203,6 +281,10 @@ def main():
"f1": results["overall_f1"], "f1": results["overall_f1"],
} }
# Class weights pour contrer le déséquilibre 97% O
print("\nCalcul des poids de classe...")
weights = compute_class_weights(raw_data, len(LABEL_LIST))
# Training # Training
args.output_dir.mkdir(parents=True, exist_ok=True) args.output_dir.mkdir(parents=True, exist_ok=True)
training_args = TrainingArguments( training_args = TrainingArguments(
@@ -218,13 +300,14 @@ def main():
load_best_model_at_end=True, load_best_model_at_end=True,
metric_for_best_model="f1", metric_for_best_model="f1",
logging_steps=50, logging_steps=50,
fp16=False, # CPU training fp16=True, # GPU training avec mixed precision
report_to="none", report_to="none",
save_total_limit=2, save_total_limit=2,
) )
data_collator = DataCollatorForTokenClassification(tokenizer) data_collator = DataCollatorForTokenClassification(tokenizer)
trainer = Trainer( trainer = WeightedNERTrainer(
class_weights=weights,
model=model, model=model,
args=training_args, args=training_args,
train_dataset=tokenized["train"], train_dataset=tokenized["train"],