- 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>
119 lines
4.0 KiB
Python
119 lines
4.0 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
build_noms_famille_gazetteer.py
|
|
Construit deux gazetteers de noms de famille français à partir du fichier INSEE.
|
|
|
|
Source : /home/dom/ai/anonymisation/data/insee/noms2008nat_txt.txt
|
|
(TSV : NOM, puis effectifs par décennie 1891-2000)
|
|
|
|
Sorties dans /home/dom/ai/anonymisation/data/insee/ :
|
|
- noms_famille_france.txt : TOUS les noms (219K), un par ligne, majuscules
|
|
- noms_famille_frequents.txt : noms avec total >= 100 ET longueur >= 3 caractères
|
|
"""
|
|
|
|
import os
|
|
from collections import Counter
|
|
|
|
INPUT_FILE = "/home/dom/ai/anonymisation/data/insee/noms2008nat_txt.txt"
|
|
OUTPUT_DIR = "/home/dom/ai/anonymisation/data/insee"
|
|
OUTPUT_ALL = os.path.join(OUTPUT_DIR, "noms_famille_france.txt")
|
|
OUTPUT_FREQ = os.path.join(OUTPUT_DIR, "noms_famille_frequents.txt")
|
|
|
|
MIN_TOTAL = 100 # seuil de fréquence pour le fichier "fréquents"
|
|
MIN_LENGTH = 3 # longueur minimale pour le fichier "fréquents"
|
|
SKIP_NAMES = {"AUTRES NOMS"}
|
|
|
|
|
|
def main():
|
|
all_names = []
|
|
freq_names = []
|
|
frequencies = [] # pour les stats de distribution
|
|
|
|
with open(INPUT_FILE, "r", encoding="utf-8") as f:
|
|
header = f.readline() # skip header
|
|
print(f"En-tête : {header.strip()}")
|
|
|
|
for line in f:
|
|
line = line.strip()
|
|
if not line:
|
|
continue
|
|
|
|
parts = line.split("\t")
|
|
nom = parts[0].strip()
|
|
|
|
if nom in SKIP_NAMES:
|
|
continue
|
|
|
|
# Calculer la fréquence totale sur toutes les décennies
|
|
total = 0
|
|
for val in parts[1:]:
|
|
val = val.strip()
|
|
try:
|
|
total += int(val)
|
|
except ValueError:
|
|
pass
|
|
|
|
# Tous les noms (uppercase, déjà le cas dans le fichier)
|
|
nom_upper = nom.upper()
|
|
all_names.append(nom_upper)
|
|
frequencies.append(total)
|
|
|
|
# Filtre pour les noms fréquents
|
|
if total >= MIN_TOTAL and len(nom_upper) >= MIN_LENGTH:
|
|
freq_names.append(nom_upper)
|
|
|
|
# Écriture des fichiers
|
|
with open(OUTPUT_ALL, "w", encoding="utf-8") as f:
|
|
f.write("\n".join(all_names) + "\n")
|
|
|
|
with open(OUTPUT_FREQ, "w", encoding="utf-8") as f:
|
|
f.write("\n".join(freq_names) + "\n")
|
|
|
|
# --- Stats ---
|
|
print(f"\n{'='*60}")
|
|
print(f"STATISTIQUES")
|
|
print(f"{'='*60}")
|
|
print(f"Fichier source : {INPUT_FILE}")
|
|
print(f"Noms totaux lus : {len(all_names):>10,}")
|
|
print(f" → {OUTPUT_ALL}")
|
|
print(f"Noms fréquents : {len(freq_names):>10,} (total >= {MIN_TOTAL}, len >= {MIN_LENGTH})")
|
|
print(f" → {OUTPUT_FREQ}")
|
|
print(f"Noms exclus (filtre): {len(all_names) - len(freq_names):>10,}")
|
|
|
|
# Distribution de fréquence
|
|
print(f"\n--- Distribution des fréquences ---")
|
|
buckets = [
|
|
(0, 0, "0 (hapax)"),
|
|
(1, 9, "1-9"),
|
|
(10, 49, "10-49"),
|
|
(50, 99, "50-99"),
|
|
(100, 499, "100-499"),
|
|
(500, 999, "500-999"),
|
|
(1000, 4999, "1 000-4 999"),
|
|
(5000, 9999, "5 000-9 999"),
|
|
(10000, 49999, "10 000-49 999"),
|
|
(50000, 99999, "50 000-99 999"),
|
|
(100000, float("inf"), "100 000+"),
|
|
]
|
|
for lo, hi, label in buckets:
|
|
count = sum(1 for freq in frequencies if lo <= freq <= hi)
|
|
if count > 0:
|
|
print(f" {label:>20s} : {count:>8,} noms")
|
|
|
|
# Top 20
|
|
print(f"\n--- Top 20 noms les plus fréquents ---")
|
|
indexed = list(zip(all_names, frequencies))
|
|
indexed.sort(key=lambda x: x[1], reverse=True)
|
|
for i, (nom, freq) in enumerate(indexed[:20], 1):
|
|
print(f" {i:>2}. {nom:<25s} {freq:>10,}")
|
|
|
|
# Quelques stats globales
|
|
total_naissances = sum(frequencies)
|
|
print(f"\nTotal naissances couvertes : {total_naissances:>12,}")
|
|
print(f"Fréquence médiane : {sorted(frequencies)[len(frequencies)//2]:>12,}")
|
|
print(f"Fréquence moyenne : {total_naissances / len(frequencies):>12,.1f}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|