Codification COICOP des produits BDF

Documentation de la démarche et du pipeline de codification automatique

À quoi sert ce pipeline ?

L’enquête Budget de Famille (BDF) vise à comprendre la structure et l’évolution de la consommation des ménages et collecte pour cela les dépenses réalisées par les ménages enquêtés. Ces dépenses remontent sous forme de libellés textuels relativement courts, souvent bruités et sémantiquement différents selon leur source (descripitions manuelles, lignes de tickets de caisse, etc.).

Pour exploiter ces données, chaque libellé doit être rattaché à un poste de la nomenclature COICOP (Classification of Individual Consumption According to Purpose). Le faire à la main est coûteux : le pipeline codif-coicop-bdf automatise cette codification en combinant plusieurs approches (règles, similarité de chaînes, machine learning supervisé, RAG) puis en les arbitrant via un LLM.

La nomenclature COICOP en bref

Un code COICOP est une suite de segments séparés par des points, de plus en plus précis :

Niveau Exemple Désignation
1 01 Section (ex. Produits alimentaires et boissons non alcoolisées)
2 01.1 Division
3 01.1.1 Groupe (ex. Pains et céréales)
4 01.1.1.1 Classe (poste le plus fin conservé par le pipeline)
5 01.1.1.1.x Poste — supprimé lors du pruning (trop granulaire)

À côté des codes « produits », des codes techniques servent aux lignes qui ne sont pas un produit consommable :

Code Sens
98.1 Courses / alimentation non détaillée
98.3 Carte bancaire (ligne « Ticket CB »)
98.4 Prélèvement
98.5 Remises / réductions
99.x Divers non codables

Davantage de contexte et échéances

La codification porte sur le millésime BDF 2026 (dont les questionnaires remontent progressivement au cours de l’année 2026).

Les résultats consolidés doivent être transmis à Eurostat en 2028.

Les travaux de mise en place d’un pipeline de codification automatique ont débuté à l’automne 2025, impliquant la MoA de l’enquête, la division IPC et le SSPlab.

À noter que la prochaine enquête BDF aura lieu en 2030 et il convient ainsi de rendre le processus de codification pérenne et reproductible pour pouvoir l’utiliser lors de ce prochain millésime.

Le pipeline étape par étape

Le pipeline est un DAG Argo (argo/codif-pipeline.yaml). Chaque étape lit/écrit sur S3 dans un dossier propre au run :

s3://projet-budget-famille/data/workflow_runs/{run_date}/{run_id}/<étape>/

Le diagramme ci-dessous montre les étapes et les fichiers qui circulent entre elles (tous au format parquet, sauf le livrable final) :

flowchart LR
  input[/"CSV d'entrée<br/>(input_file, mode prod)"/] --> PRE[preprocessing]
  PRE -- "raw_test.parquet (éval)<br/>observations.parquet (prod)" --> REG[codif-regex]
  REG -- raw_test_without_regex.parquet --> PRU[prune]
  REG -- raw_test_without_regex.parquet --> LCS[codif-lcs]
  REG -- raw_test_without_regex.parquet --> TTC[run-ttc]
  PRU -- nomenclature_pruned.parquet --> VDB[create-vector-db]
  PRU -- "annotations_train_pruned<br/>+ suggester_pruned" --> VDBA[create-vector-db-annotations]
  VDB -.->|"collection Qdrant"| RAG[run-rag]
  VDBA -.->|"collection Qdrant"| RAGA[run-rag-annotations]
  PRU -- annotations_test_pruned.parquet --> RAG
  PRU -- annotations_test_pruned.parquet --> RAGA
  LCS -- raw_test_LCS.parquet --> DEC[decide-coicop]
  RAG -- predictions.parquet --> DEC
  RAGA -- predictions.parquet --> DEC
  TTC -- predictions.parquet --> DEC
  PRU -- mapping_lvl4.parquet --> DEC
  DEC -- predictions.parquet --> FIN[final-output]
  REG -- REGEX_pred.parquet --> FIN
  DEC -- predictions.parquet --> REP[report]
  FIN --> out[/"CSV livré<br/>(+ predicted_code)"/]
  REP --> html[/report.html/]
  style VDB stroke-dasharray: 5 5
  style VDBA stroke-dasharray: 5 5

Seuls les deux nœuds en pointillé (create-vector-db, create-vector-db-annotations) sont skippables (-p skip-vector-db=true) : les collections Qdrant sont réutilisées d’un run à l’autre. L’étape prune, elle, n’est jamais sautée : elle produit à chaque run le jeu à coder pruné et la table de mapping dont l’aval a besoin.

NoteUn seul workflow, deux modes

Le dépôt contient un unique workflow de codification, argo/codif-pipeline.yaml, qui fonctionne en deux modes selon le paramètre input_file : production (input_file non vide — le fichier externe est codifié et livré par final-output) ou évaluation (input_file vide — c’est le split test des annotations qui est codifié, et le rapport mesure l’exactitude). Chaque étape clone le dépôt sur la branche donnée par le paramètre git-branch (défaut : main). argo/ttc-pipeline.yaml est un workflow séparé, dédié à l’entraînement du classifieur TTC.

# Étape Rôle Page
1 preprocessing Construit toujours les annotations (complet + train/test) ; en prédiction, prépare aussi les observations à coder
2 codif-regex Code les libellés évidents par règles regex ; point unique d’échantillonnage
3 prune Troncature niveau 4 + élagage des hiérarchies linéaires : produit tous les artefacts prunés
4 codif-lcs Code par similarité de chaîne (LCS) sur un pool de référence
5 run-ttc Classifieur neuronal basique (caisses + fine-tuning BDF 2024)
6 create-vector-db / run-rag Codification sémantique par RAG sur les notices COICOP prunées
7 create-vector-db-annotations / run-rag-annotations Codification par RAG sur exemples déjà codifiés (few-shot)
8 decide-coicop Arbitrage final LLM-as-judge entre LCS / RAG notices / RAG annotations / TTC
9 final-output Assemble le résultat utilisateur (regex + décision LLM)
10 report Rapport Quarto (qualité ou suivi de prédiction)

Lancer le pipeline

Un script d’aide est présent dans le repo : codif-coicop-bdf/argo/argo_helper.md.

Il donne les commandes d’installation et de lancement. Par ailleurs, le script de paramétrages du workflow se trouve ici codif-coicop-bdf/argo/params.yaml (il permet notamment de choisir sur quel fichier s’applique la codification, choisir entre une approche de production courante ou d’évaluation, coder sur un échantillon de produits, etc.).

Fil rouge

Quatre lignes réelles du CSV sont suivies de bout en bout dans les pages suivantes :

Libellé (NAT_DEP) Enseigne Montant Devenir attendu
Bagu. Tradition U Blé Bretagne U (Liffré) 1,00 € produit alimentaire → pain 01.1.1.x (via modèles)
Illisible 0,00 € non codable → retiré, ou capté par la règle ^illisible$98.4
Ticket CB Station Netto 40,24 € ligne technique mais non captée par les regex (libellé non standardisé) → passe aux modèles
Max garden flowers balle surprise Action 3,99 € produit ambigu → arbitrage LLM
Astuce

Les règles regex sont surtout ancrées (^…$) et ne reconnaissent que des libellés standardisés (carte bancaire, prelevement, courses, restaurant…). Sur cet extrait BDF, les libellés réels (Ticket CB, Prlv Sepa Bouygues…) ne correspondent pas exactement : la plupart des lignes franchissent donc l’étape regex et sont codées par les modèles puis arbitrées par le LLM. Voir 2. Codif regex.

Chaque page d’étape reprend la même structure : Rôle · Entrées · Traitement · Exemple sur le fil rouge · Sorties.

# Pipeline complet en mode évaluation (input_file vide)
argo submit argo/codif-pipeline.yaml --parameter-file argo/params.yaml

# Mode production : sur un fichier d'entrée et son mappage de colonnes
argo submit argo/codif-pipeline.yaml \
  -p input_file=s3://projet-budget-famille/data/workflow_inputs/mon_fichier.csv \
  -p text_column=NAT_DEP -p shop_column=MAG_DEP -p budget_column=MONT_DEP

# Limiter le test à N observations (sampling centralisé à codif-regex, hérité
# par tous les classifieurs) : en mode évaluation
argo submit argo/codif-pipeline.yaml -p sample-annotations=100
# ... et en mode production (input_file non vide)
argo submit argo/codif-pipeline.yaml -p input_file=... -p sample-observations=100

# Réutiliser les collections Qdrant existantes (pas de reconstruction)
argo submit argo/codif-pipeline.yaml -p skip-vector-db=true

Pour relancer ou déboguer une seule étape (via Argo ou en local), voir Lancer une étape individuellement. Les termes et colonnes du pipeline sont définis dans le glossaire. Des présentations résument le pipeline pour différents publics.