# Como normalizar dados médicos

> Tutorial: transforme dados médicos de várias fontes numa forma comparável — consulta LOINC, unidades UCUM, datas ISO, intervalos de referência, sem duplicados em novas tentativas e validação contra o perfil laboratorial europeu.

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

**Normalizar dados médicos significa transformar valores que chegam em muitas formas numa forma comparável: o mesmo código para o mesmo teste, o mesmo sistema de unidades, datas num único formato, cada valor com o seu intervalo de referência e a sua origem, e sem duplicados.** Este tutorial mostra como fazer isso antes de os dados chegarem a um registo HL7 FHIR R4: consulta de códigos LOINC e ATC, utilização de unidades UCUM, recusa de datas ambíguas, manutenção de intervalos, evitação de duplicados em novas tentativas e verificação do resultado contra o perfil laboratorial europeu. Cada resposta apresentada provém da API Anpheros.

## A sua importância

O mesmo resultado de HbA1c pode chegar até si como "HbA1c 6,4 %", "Hemoglobina glicozilada: 6.4", "Hemoglobina glicada 46 mmol/mol" ou apenas um código de laboratório que um único laboratório compreende. Até que estes sejam um código com uma unidade:

- um gráfico da HbA1c do paciente ao longo do tempo mostra três linhas não relacionadas;
- um alerta sobre "HbA1c acima de 6,5 %" falha dois dos valores;
- um modelo de IA vê quatro factos em vez de uma tendência;
- outro sistema que recebe o registo não o consegue interpretar.

A normalização pertence ao ponto onde os dados entram no registo, uma vez, não em cada aplicação que os lê posteriormente.

## O que um valor normalizado tem

| Parte | Forma normalizada | Exemplo |
|---|---|---|
| O que foi medido | um código de um sistema padrão | LOINC `4548-4` (HbA1c), RxNorm `6809` (metformina), ICD-10 `E11` (diabetes tipo 2) |
| O valor | um número, ou texto apenas quando o resultado não é numérico | `6.4` |
| A unidade | UCUM | `%`, `mg/dL`, `mm[Hg]`, `kg` |
| Quando | uma data-hora ISO 8601, com fuso horário quando a hora é relevante | `2026-10-01T07:30:00Z` |
| Intervalo normal | baixo e alto, na mesma unidade | `4.0`–`5.6` |
| Origem | quem o produziu e de que sistema | `import` de `labx` |
| Identidade | algo que torna uma repetição reconhecível | uma chave de idempotência ou um identificador de origem |

Qual sistema de códigos corresponde a que tipo de recurso está listado em [Sistemas de códigos FHIR](https://developers.anpheros.com/pt/guides/fhir-code-systems).

## Passo 1: Encontrar o código

Pesquise a terminologia da plataforma pelo nome em inglês ou romeno, ou por abreviatura:

```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"
```

Ambos retornam o mesmo conceito:

```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}
```

Para medicamentos, [Anpheros Search](https://developers.anpheros.com/pt/guides/anpheros-search) encontra a substância pelo nome ou marca e fornece o seu código de ingrediente RxNorm e números de produto da EMA:

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

O campo `unit` é a unidade que o LOINC espera para esse teste. Use-o para verificar o que recebeu. Construa o mapeamento dos nomes de cada origem para códigos uma vez, por origem, e mantenha-o na sua integração. Não adivinhe no momento da escrita: quando um nome é ambíguo e nada na origem o resolve, deixe-o sem mapeamento e pergunte à origem. [Como importar resultados de laboratório para um registo FHIR](https://developers.anpheros.com/pt/guides/import-lab-results-fhir) mostra como os marcadores de laboratório sem mapeamento são mantidos e reportados.

## Passo 2: Escrever com códigos, unidades e intervalos

```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-…"}
```

Quando envia apenas o código, a plataforma preenche o nome LOINC padrão, tanto na API REST como na API FHIR (`/fhir/R4`), para que todas as aplicações leiam o mesmo `display`. Um `display` que envia por si próprio é mantido como está.

Mantenha também a redação original. Para um relatório de laboratório, `code.text` na Observação FHIR contém o nome do laboratório ("Hemoglobina glicozilada (HbA1c)") ao lado da codificação LOINC. O paciente ainda reconhece o seu relatório em papel, e nada se perde se o mapeamento for alguma vez questionado.

## Passo 3: Unidades

Utilize códigos UCUM: `mg/dL`, `mmol/L`, `%`, `mm[Hg]`, `kg`, `cm`, `/min`, `Cel`. Duas regras evitam a maioria dos erros:

- **Não converta silenciosamente.** Se um laboratório reportar glicose em `mmol/L` e a sua aplicação exibir `mg/dL`, armazene o que o laboratório mediu e converta apenas quando o exibir. O valor armazenado permanece rastreável ao relatório.
- **Verifique a unidade contra o código.** Os códigos LOINC são específicos: HbA1c em `%` é `4548-4`, enquanto HbA1c em `mmol/mol` é um código LOINC diferente. Um valor cuja unidade não corresponda à unidade esperada do código é um erro de mapeamento, não um problema de conversão.

A Anpheros não converte unidades por si; armazena a unidade que envia.

## Passo 4: Datas

Converta as datas para ISO 8601 antes de as gravar, utilizando o formato conhecido da origem. `01.10.2026` é 1 de outubro na Roménia e em muitos países europeus, mas `10/01/2026` é 1 de outubro apenas nos Estados Unidos. A API recusa qualquer coisa que não seja ISO, em vez de adivinhar:

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

O conector de laboratório é a exceção: aceita `DD.MM.YYYY` e `DD/MM/YYYY` porque sabe que está a ler um relatório europeu.

Para medições em que a hora do dia é importante (pressão arterial, glicose, doses de medicação), envie a hora com o seu fuso horário. Uma leitura às 23:30 em Bucareste é no dia anterior em UTC, e o paciente espera-a no dia em que a fez.

## Passo 5: sem duplicados

Duplicados surgem de novas tentativas, do mesmo relatório enviado duas vezes e do mesmo valor a chegar através de duas rotas.

- **Novas tentativas:** envie um `Idempotency-Key` que identifique o valor na origem, por exemplo, o ID do relatório e o teste. Enviar o mesmo pedido novamente com a mesma chave retorna a primeira resposta e não armazena nada de novo. Os SDKs adicionam um a cada criação.
- **O mesmo relatório duas vezes:** o conector de laboratório constrói um identificador estável por linha a partir do relatório, código, data e valor, e ignora linhas já importadas.
- **Duas rotas:** armazene o ID próprio do sistema de origem com `X-Anpheros-Origin-Id` (ou em `identifier` nos recursos FHIR), e pesquise por ele antes de escrever valores que possam retornar por outro caminho.

## Passo 6: Verificação contra um perfil

Para resultados de laboratório, pergunte à plataforma como um recurso se compara ao perfil de relatório de laboratório HL7 Europe antes de confiar nele:

```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": "%"}
}'
```

Este resultado não normalizado obtém uma lista precisa:

```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"]}]}
```

Cada problema mapeia para um dos passos acima. Execute `$validate` nos seus testes de integração, com amostras reais de cada fonte.

## Passo 7: manter a origem

A normalização altera a forma como um valor é escrito, nunca de onde veio. Envie `author_type` (`device`, `import`, `practitioner`, `patient`) e `X-Anpheros-Source-System` com cada escrita. É isso que permite a um médico, a um auditor ou a um modelo de IA distinguir um resultado de laboratório de um valor digitado em casa. Ver [Proveniência de dados médicos explicada](https://developers.anpheros.com/pt/guides/medical-data-provenance).

## Checklist

- [ ] Cada fonte tem um mapeamento dos seus nomes para LOINC / ATC / ICD-10, mantido na sua integração
- [ ] Nomes ambíguos permanecem sem mapeamento e são reportados, nunca adivinhados
- [ ] Unidades UCUM, correspondendo ao código; sem conversão silenciosa
- [ ] Datas ISO 8601, com fusos horários onde a hora é relevante
- [ ] Intervalos de referência mantidos com valores de laboratório
- [ ] Redação original mantida (`code.text`)
- [ ] Chaves de idempotência ou IDs de origem em cada escrita
- [ ] `author_type` e sistema de origem em cada escrita
- [ ] `$validate` em testes para resultados de laboratório

## Perguntas frequentes

### O que é a normalização de dados médicos?
Converter dados de saúde de diferentes fontes numa única forma padrão: códigos partilhados (LOINC para testes e medições, ICD-10 para diagnósticos, ATC para medicamentos), unidades UCUM, datas ISO, intervalos de referência e uma fonte registada, para que os valores de diferentes sistemas possam ser comparados, combinados e trocados.

### Devo converter todos os valores para uma única unidade?
Armazene a unidade em que a fonte mediu, desde que seja uma unidade UCUM válida que corresponda ao código, e converta ao apresentar ou analisar. Isto mantém cada valor armazenado rastreável ao seu relatório original.

### A normalização pode ser totalmente automática?
Na maioria dos casos. Códigos na fonte, nomes conhecidos e unidades bem formadas podem ser mapeados automaticamente. Nomes ambíguos e códigos locais desconhecidos necessitam de uma decisão humana uma vez por fonte, após a qual o mapeamento é automático.

## Relacionado

- [Sistemas de código FHIR](https://developers.anpheros.com/pt/guides/fhir-code-systems)
- [Como importar resultados laboratoriais para um registo FHIR](https://developers.anpheros.com/pt/guides/import-lab-results-fhir)
- [Proveniência de dados médicos explicada](https://developers.anpheros.com/pt/guides/medical-data-provenance)
- [Interoperabilidade de dados de saúde](https://developers.anpheros.com/pt/guides/interoperability)
- [API de dados médicos](https://developers.anpheros.com/pt/guides/medical-data-api)
