# Comment normaliser les données médicales

> Tutoriel : transformer les données médicales provenant de nombreuses sources en une forme comparable — recherche LOINC, unités UCUM, dates ISO, plages de référence, pas de doublons lors de nouvelles tentatives, et validation par rapport au profil de laboratoire européen.

Source: https://developers.anpheros.com/fr/guides/normalize-medical-data

**La normalisation des données médicales consiste à transformer des valeurs arrivant sous de nombreuses formes en une forme comparable : le même code pour le même test, le même système d'unités, des dates dans un seul format, chaque valeur avec sa plage de référence et sa source, et aucun doublon.** Ce tutoriel montre comment procéder avant que les données n'atteignent un enregistrement HL7 FHIR R4 : recherche des codes LOINC et ATC, utilisation des unités UCUM, refus des dates ambiguës, conservation des plages, évitement des doublons lors de nouvelles tentatives et vérification du résultat par rapport au profil de laboratoire européen. Chaque réponse présentée provient de l'API Anpheros.

## Pourquoi c'est important

Le même résultat d'HbA1c peut vous parvenir sous la forme de « HbA1c 6,4 % », « Hemoglobina glicozilata: 6.4 », « Glycated haemoglobin 46 mmol/mol » ou d'un code de laboratoire que seul un laboratoire comprend. Tant que ces valeurs ne sont pas un seul code avec une seule unité :

- un graphique de l'HbA1c du patient au fil du temps affiche trois lignes sans rapport ;
- une alerte sur « HbA1c supérieur à 6,5 % » manque deux des valeurs ;
- un modèle d'IA voit quatre faits au lieu d'une tendance ;
- un autre système recevant l'enregistrement ne peut pas l'interpréter.

La normalisation doit avoir lieu au point d'entrée des données dans l'enregistrement, une seule fois, et non dans chaque application qui les lit ultérieurement.

## Ce qu'une valeur normalisée contient

| Partie | Forme normalisée | Exemple |
|---|---|---|
| Ce qui a été mesuré | un code d'un système standard | LOINC `4548-4` (HbA1c), RxNorm `6809` (metformine), ICD-10 `E11` (diabète de type 2) |
| La valeur | un nombre, ou du texte uniquement lorsque le résultat n'est pas numérique | `6.4` |
| L'unité | UCUM | `%`, `mg/dL`, `mm[Hg]`, `kg` |
| Quand | une date-heure ISO 8601, avec fuseau horaire lorsque l'heure est importante | `2026-10-01T07:30:00Z` |
| Plage normale | bas et haut, dans la même unité | `4.0`–`5.6` |
| Source | qui l'a produit et de quel système | `import` de `labx` |
| Identité | quelque chose qui rend une répétition reconnaissable | une clé d'idempotence ou un identifiant de source |

Le système de codes qui correspond à chaque type de ressource est listé dans [Systèmes de codes FHIR](https://developers.anpheros.com/fr/guides/fhir-code-systems).

## Étape 1 : trouver le code

Recherchez la terminologie de la plateforme par nom anglais ou roumain, ou par abréviation :

```bash
curl "https://platform.anpheros.com/v1/terminology/loinc?q=hba1c" -H "Authorization: Bearer $KEY"
curl "https://platform.anpheros.com/v1/terminology/loinc?q=hemoglobina%20glicozilata" -H "Authorization: Bearer $KEY"
```

Les deux renvoient le même concept :

```json
{"data": [{"system": "http://loinc.org", "code": "4548-4", "display": "Hemoglobin A1c/Hemoglobin.total in Blood",
           "display_ro": "Hemoglobină glicozilată (HbA1c)", "category": "laboratory", "unit": "%"}], "total": 1}
```

Pour les médicaments, [Anpheros Search](https://developers.anpheros.com/fr/guides/anpheros-search) trouve la substance par nom ou marque et donne son code d'ingrédient RxNorm et ses numéros de produit EMA :

```bash
curl "https://platform.anpheros.com/v1/search?q=metformin&type=treatment" -H "Authorization: Bearer $KEY"
```

Le champ `unit` est l'unité attendue par LOINC pour ce test. Utilisez-le pour vérifier ce que vous avez reçu. Construisez le mappage de chaque nom propre à sa source vers des codes une fois, par source, et conservez-le dans votre intégration. Ne devinez pas au moment de l'écriture : lorsqu'un nom est ambigu et que rien dans la source ne le résout, laissez-le non mappé et demandez à la source. [Comment importer les résultats de laboratoire dans un enregistrement FHIR](https://developers.anpheros.com/fr/guides/import-lab-results-fhir) montre comment les marqueurs de laboratoire non mappés sont conservés et signalés.

## Étape 2 : Écrire avec des codes, des unités et des plages

```bash
curl -X POST "https://platform.anpheros.com/v1/patients/$PID/observations" -H "Authorization: Bearer $KEY" \
     -H "Content-Type: application/json" -H "Idempotency-Key: lab-77-hba1c" -d '{
  "code": "4548-4", "category": "laboratory",
  "value": 6.4, "unit": "%", "effective_at": "2026-10-01T07:30:00Z",
  "reference_range": {"low": 4.0, "high": 5.6},
  "author_type": "import"
}'
```

```json
{"id": "3296315c-…", "code": "4548-4", "system": "http://loinc.org", "display": "Hemoglobin A1c/Hemoglobin.total in Blood",
 "category": "laboratory", "effective_at": "2026-10-01T07:30:00Z", "value": 6.4, "unit": "%",
 "reference_range": {"low": 4.0, "high": 5.6}, "status": "final", "fhir": "Observation/3296315c-…"}
```

Lorsque vous envoyez uniquement le code, la plateforme remplit le nom LOINC standard, sur l'API REST comme sur l'API FHIR (`/fhir/R4`), de sorte que chaque application lise la même `display`. Une `display` que vous envoyez vous-même est conservée telle quelle.

Gardez également la formulation originale. Pour un rapport de laboratoire, `code.text` sur l'Observation FHIR contient le nom du laboratoire ("Hemoglobina glicozilata (HbA1c)") à côté du codage LOINC. Le patient reconnaît toujours son rapport papier, et rien ne est perdu si le mappage est remis en question.

## Étape 3 : unités

Utilisez les codes UCUM : `mg/dL`, `mmol/L`, `%`, `mm[Hg]`, `kg`, `cm`, `/min`, `Cel`. Deux règles permettent d'éviter la plupart des erreurs :

- **Ne pas convertir silencieusement.** Si un laboratoire rapporte le glucose en `mmol/L` et que votre application affiche `mg/dL`, stockez ce que le laboratoire a mesuré et convertissez lors de l'affichage. La valeur stockée reste traçable au rapport.
- **Vérifiez l'unité par rapport au code.** Les codes LOINC sont spécifiques : HbA1c en `%` est `4548-4`, tandis que HbA1c en `mmol/mol` correspond à un code LOINC différent. Une valeur dont l'unité ne correspond pas à l'unité attendue du code est une erreur de mappage, pas un problème de conversion.

Anpheros ne convertit pas les unités pour vous ; il stocke l'unité que vous envoyez.

## Étape 4 : dates

Convertissez les dates au format ISO 8601 avant de les écrire, en utilisant le format connu de la source. `01.10.2026` correspond au 1er octobre en Roumanie et dans de nombreux pays européens, mais `10/01/2026` correspond au 1er octobre uniquement aux États-Unis. L'API refuse tout ce qui n'est pas au format ISO, plutôt que de deviner :

```json
{"error": {"type": "invalid", "message": "Input should be a valid datetime or date, invalid character in year (at effective_at)", "field": "effective_at"}}
```

Le connecteur de laboratoire fait exception : il accepte `DD.MM.YYYY` et `DD/MM/YYYY` car il sait qu'il lit un rapport européen.

Pour les mesures où l'heure de la journée est importante (tension artérielle, glycémie, doses de médicaments), envoyez l'heure avec son fuseau horaire. Une mesure à 23h30 à Bucarest correspond à la veille en UTC, et le patient s'attend à ce qu'elle soit enregistrée le jour où il l'a prise.

## Étape 5 : pas de doublons

Les doublons proviennent des nouvelles tentatives, d'un même rapport envoyé deux fois et d'une même valeur arrivant par deux canaux.

- **Nouvelles tentatives :** envoyez un `Idempotency-Key` qui identifie la valeur dans la source, par exemple l'identifiant du rapport et le test. L'envoi de la même requête à nouveau avec la même clé renvoie la première réponse et ne stocke rien de nouveau. Les SDK ajoutent un à chaque création.
- **Le même rapport deux fois :** le connecteur de laboratoire construit un identifiant stable par ligne à partir du rapport, du code, de la date et de la valeur, et ignore les lignes déjà importées.
- **Deux canaux :** stockez l'identifiant propre au système source avec `X-Anpheros-Origin-Id` (ou dans `identifier` sur les ressources FHIR), et recherchez-le avant d'écrire des valeurs qui peuvent revenir par un autre chemin.

## Étape 6 : Vérification par rapport à un profil

Pour les résultats de laboratoire, demandez à la plateforme comment une ressource se compare au profil de rapport de laboratoire HL7 Europe avant de vous y fier :

```bash
curl -X POST "https://platform.anpheros.com/fhir/R4/Observation/\$validate?profile=eu-lab" -H "Authorization: Bearer $KEY" \
     -H "Content-Type: application/fhir+json" -d '{
  "resourceType": "Observation", "status": "final",
  "category": [{"coding": [{"system": "http://terminology.hl7.org/CodeSystem/observation-category", "code": "laboratory"}]}],
  "code": {"text": "HbA1c"}, "subject": {"reference": "Patient/'$PID'"},
  "valueQuantity": {"value": 6.4, "unit": "%"}
}'
```

Ce résultat non normalisé obtient une liste précise :

```json
{"resourceType": "OperationOutcome", "issue": [
  {"severity": "error", "code": "invalid", "diagnostics": "Observation.code must carry a LOINC coding.", "expression": ["Observation.code"]},
  {"severity": "error", "code": "required", "diagnostics": "Observation.effective[x] is required.", "expression": ["Observation.effective"]},
  {"severity": "warning", "code": "business-rule", "diagnostics": "valueQuantity should carry a UCUM system and code.", "expression": ["Observation.valueQuantity"]},
  {"severity": "warning", "code": "informational", "diagnostics": "No referenceRange: interpretation will need the laboratory's ranges.", "expression": ["Observation.referenceRange"]},
  {"severity": "information", "code": "informational", "diagnostics": "No performer (laboratory) recorded.", "expression": ["Observation.performer"]},
  {"severity": "information", "code": "informational", "diagnostics": "No issued time (when the laboratory released the result).", "expression": ["Observation.issued"]}]}
```

Chaque problème correspond à l'une des étapes ci-dessus. Exécutez `$validate` dans vos tests d'intégration, avec des échantillons réels de chaque source.

## Étape 7 : Conserver la source

La normalisation modifie la manière dont une valeur est écrite, jamais d'où elle provient. Envoyez `author_type` (`device`, `import`, `practitioner`, `patient`) et `X-Anpheros-Source-System` à chaque écriture. C'est ce qui permet à un médecin, un auditeur ou un modèle d'IA de distinguer un résultat de laboratoire d'une valeur saisie à domicile. Voir [Explication de la provenance des données médicales](https://developers.anpheros.com/fr/guides/medical-data-provenance).

## Liste de contrôle

- [ ] Chaque source a un mappage de ses noms vers LOINC / ATC / ICD-10, conservé dans votre intégration
- [ ] Les noms ambigus restent non mappés et sont signalés, jamais devinés
- [ ] Unités UCUM, correspondant au code ; pas de conversion silencieuse
- [ ] Dates ISO 8601, avec fuseaux horaires lorsque l'heure est importante
- [ ] Plages de référence conservées avec les valeurs de laboratoire
- [ ] Formulation originale conservée (`code.text`)
- [ ] Clés d'idempotence ou identifiants source sur chaque écriture
- [ ] `author_type` et système source sur chaque écriture
- [ ] `$validate` dans les tests pour les résultats de laboratoire

## Foire aux questions

### Qu'est-ce que la normalisation des données médicales ?
Conversion des données de santé provenant de différentes sources en une forme standard unique : codes partagés (LOINC pour les tests et mesures, ICD-10 pour les diagnostics, ATC pour les médicaments), unités UCUM, dates ISO, plages de référence et une source enregistrée, afin que les valeurs de différents systèmes puissent être comparées, combinées et échangées.

### Dois-je convertir toutes les valeurs en une seule unité ?
Stockez l'unité dans laquelle la source a mesuré, tant qu'il s'agit d'une unité UCUM valide correspondant au code, et convertissez lors de l'affichage ou de l'analyse. Cela permet de retracer chaque valeur stockée jusqu'à son rapport d'origine.

### La normalisation peut-elle être entièrement automatique ?
En grande partie. Les codes de la source, les noms connus et les unités bien formées peuvent être mappés automatiquement. Les noms ambigus et les codes locaux inconnus nécessitent une décision humaine une fois par source, après quoi le mappage est automatique.

## Liens connexes

- [Systèmes de codes FHIR](https://developers.anpheros.com/fr/guides/fhir-code-systems)
- [Comment importer des résultats de laboratoire dans un enregistrement FHIR](https://developers.anpheros.com/fr/guides/import-lab-results-fhir)
- [Provenance des données médicales expliquée](https://developers.anpheros.com/fr/guides/medical-data-provenance)
- [Interopérabilité des données de santé](https://developers.anpheros.com/fr/guides/interoperability)
- [API de données médicales](https://developers.anpheros.com/fr/guides/medical-data-api)
