MicroSUS.jl
Microdados do DATASUS em Julia — leitura streaming de arquivos .dbc (PKWare DCL) e .dbf com memória constante, schemas tipados por sistema (SIM, SINASC, SIH, SIA, CNES, SINAN), transcodificação CP850/Latin-1 → UTF-8, download com cache local (Scratch.jl) e interface Tables.jl com partições.
Comece pela página Exemplos práticos (iniciantes): um passo a passo do zero, da instalação ao primeiro gráfico, com cada linha de código explicada.
Instalação
using Pkg
Pkg.add("MicroSUS")Julia ≥ 1.9. Dependências: DataFrames, Tables, InlineStrings, PooledArrays, Scratch, Downloads, Dates. Arrow é opcional (extensão condicional).
Começo rápido
using MicroSUS, DataFrames
# download com cache local — não rebaixa o que já está no disco
caminho = baixar(:sim, "PE"; ano = 2023)
# totalmente tipado: datas → Date, a IDADE do SIM → anos, categóricas →
# PooledArray, texto → InlineStrings, CP850 → UTF-8
df = DataFrame(ler(caminho))
# seleção de colunas + filtro de linhas DENTRO DO LEITOR
t = ler(caminho;
colunas = [:DTOBITO, :CAUSABAS, :CODMUNRES, :IDADE, :SEXO],
filtro = r -> eh_agressao(r[:CAUSABAS])) # CVLI: X85–Y09 + Y87.1
cvli = DataFrame(t)
# processamento em lotes, memória constante
using Tables
for lote in Tables.partitions(ler(caminho; tamanho_lote = 50_000))
# `lote` é um NamedTuple de vetores — uma tabela Tables.jl válida
end
# .dbc → Arrow em streaming
using Arrow
converter(caminho, "do_pe_2023.arrow";
colunas = [:DTOBITO, :CAUSABAS, :CODMUNRES])Funções
fetch_datasus — tudo em um: baixa, lê e concatena
A interface de mais alto nível: resolve a URL, baixa (com cache), lê, concatena as partes e opcionalmente padroniza os códigos em rótulos legíveis.
# óbitos de Pernambuco, 2019–2023, já padronizados
do_pe = fetch_datasus(:SIM_DO; uf = "PE", anos = 2019:2023)
# nascidos vivos de PE e BA, com os códigos brutos
dn = fetch_datasus(:SINASC; uf = ["PE", "BA"], anos = 2022, processar = false)
# internações hospitalares de PE no primeiro semestre de 2024
rd = fetch_datasus(:SIH_RD; uf = "PE", anos = 2024, meses = 1:6)
# dengue no Brasil inteiro (fonte nacional: uf é ignorada)
dengue = fetch_datasus(:SINAN_DENGUE; anos = 2024)O resultado concatena por nome de coluna (cols = :union) e acrescenta as colunas de origem UF_ARQUIVO, ANO_ARQUIVO e, nas fontes mensais, MES_ARQUIVO. Arquivos ausentes no FTP geram @warn e são pulados.
Use fontes para listar todas as fontes disponíveis com seus identificadores, descrições, periodicidade e faixa de anos, ou fonte para inspecionar uma só:
fontes() |> DataFrame
fonte(:SIM_DO)ler — leitor de tabelas em streaming
Abre um .dbc ou .dbf como uma TabelaDBC preguiçosa. Nada é lido até a iteração. A seleção de colunas e o filtro de linhas acontecem dentro do leitor: colunas não pedidas nunca são materializadas, e o filtro decodifica só o campo consultado antes de decidir se guarda a linha.
ler(caminho)
ler(caminho; colunas = [:DTOBITO, :IDADE, :SEXO])
ler(caminho; filtro = r -> eh_agressao(r[:CAUSABAS]))
ler(caminho; schema = :auto, encoding = :cp850, pool = false)
ler(caminho; tamanho_lote = 50_000)| kwarg | default | descrição |
|---|---|---|
colunas | nothing (todas) | Vector{Symbol}; colunas fora da lista nunca são materializadas |
filtro | nothing | RegistroDBF -> Bool, roda antes do parse das colunas |
tamanho_lote | 100_000 | linhas por partição — o teto de memória do pipeline |
schema | :auto | deduzido do prefixo do arquivo; ou :sim, :sinasc, :sih, :sia, :cnes, :sinan, um Dict{Symbol,Symbol} seu, ou nothing (só a tipagem do DBF) |
encoding | :auto | language driver do cabeçalho (DATASUS ⇒ :cp850); ou :cp850, :latin1, :cp1252, :utf8 |
pool | true | PooledArray nas categóricas do schema |
Devolve uma TabelaDBC — uma tabela preguiçosa que implementa Tables.partitions (lotes) e Tables.columns (materialização completa). Funciona direto em DataFrame(t), Arrow.write(saida, t) etc.
baixar / baixar_sinan — download com cache
Baixam arquivos .dbc do servidor FTP do DATASUS com cache local (Scratch.jl). Chamadas repetidas devolvem o caminho em cache, sem rebaixar.
# SIM, SINASC, SIH, SIA, CNES — por UF
baixar(:sim, "PE"; ano = 2023) # um arquivo
baixar(:sim, "PE"; anos = 2013:2023) # vários, em paralelo
baixar(:sih, "PE"; anos = [2023], meses = 1:12) # mensal
# SINAN — arquivos nacionais (sem UF: filtre pela residência no `ler`)
baixar_sinan(:dengue; ano = 2024) # DENGBR24.dbc
baixar_sinan(:zika; anos = 2016:2020) # vários anos, em paralelo| Função | Sistema | Periodicidade |
|---|---|---|
baixar(:sim, uf) | SIM (Mortalidade) | anual |
baixar(:sinasc, uf) | SINASC (Nascidos Vivos) | anual |
baixar(:sih, uf) | SIH (Hospitalar) | mensal |
baixar(:sia, uf) | SIA (Ambulatorial) | mensal |
baixar(:cnes, uf) | CNES (Estabelecimentos) | mensal |
baixar_sinan(agravo) | SINAN (Agravos de notificação) | anual (nacional) |
As duas funções caem automaticamente nas pastas de dados preliminares (PRELIM/) quando o arquivo consolidado ainda não existe, com um @warn.
Agravos do SINAN
:dengue, :chikungunya, :zika, :meningite, :tuberculose, :hanseniase, :hepatites, :violencia, :leishmaniose_visceral, :leishmaniose_tegumentar, :esquistossomose, :febre_tifoide, :intoxicacao_exogena, :acidente_animais
Funções de URL
url_arquivo(:sinasc, "BA"; ano = 2022) # só a URL
url_arquivo(:sim, "PE"; ano = 2025, prelim = true)
url_sinan(:meningite; ano = 2023)converter — .dbc → Arrow em streaming
Converte .dbc/.dbf para Arrow em streaming (um record batch por lote). Memória O(tamanho_lote). Requer using Arrow.
using Arrow
converter(caminho, "saida.arrow")
converter(caminho, "saida.arrow";
colunas = [:DTOBITO, :CAUSABAS, :CODMUNRES],
filtro = r -> eh_agressao(r[:CAUSABAS]))materializar — materializar as partições
Consome todas as partições e concatena as colunas num NamedTuple de vetores. Equivale ao que DataFrame(t) chama internamente.
nt = materializar(ler(caminho))descomprime_dbc_para_dbf — DBC → DBF cru
Converte .dbc → .dbf em streaming (memória constante, equivalente ao dbc2dbf do pacote R read.dbc).
descomprime_dbc_para_dbf("entrada.dbc", "saida.dbf")Padronização das fontes
process_sim e process_sinasc convertem os códigos crus em rótulos legíveis, datas em texto em Date e numéricos armazenados como texto em números. São chamados automaticamente por fetch_datasus quando processar = true (o default).
df = fetch_datasus(:SIM_DO; uf = "PE", anos = 2023) # já padronizado
bruto = fetch_datasus(:SIM_DO; uf = "PE", anos = 2023, processar = false)
padronizado = process_sim(bruto) # equivalenteNo SIM isso rotula sexo, raça/cor, estado civil, escolaridade, local de ocorrência e circunstância do óbito, e cria a coluna IDADE_ANOS em anos completos. No SINASC, rotula tipo de parto, gravidez, escolaridade e estado civil da mãe, consultas de pré-natal e local de nascimento.
Decodificação de idade
decodifica_idade_sim / decodifica_idade_sinan
Convertem a codificação de idade do SIM (3 dígitos) ou do SINAN (4 dígitos) para anos:
decodifica_idade_sim("425") # 25.0
decodifica_idade_sim("501") # 101.0
decodifica_idade_sim("310") # 0.833… (10 meses)
decodifica_idade_sim("999") # missing
decodifica_idade_sinan("4025") # 25.0
decodifica_idade_sinan("5010") # 110.0| 1º dígito | unidade | exemplo (SIM) | anos |
|---|---|---|---|
| 0 | minutos | "030" | 30 / 525 960 |
| 1 | horas | "112" | 12 / 8 766 |
| 2 | dias | "230" | 30 / 365,25 |
| 3 | meses | "310" | 10 / 12 |
| 4 | anos | "425" | 25,0 |
| 5 | 100 + valor | "501" | 101,0 |
| 9 | ignorada | "999" | missing |
Códigos de município do IBGE
dv_ibge(261110) # 1 (dígito verificador)
codigo7_ibge(261110) # 2611101 (SIM/SINASC usam 6; o IBGE, 7)
codigo6_ibge(2611101) # 261110, validando o DVCapítulos da CID-10
capitulo_cid10("X954") # (numeral="XX", nome="Causas externas …")
capitulo_cid10("I219") # (numeral="IX", nome="Doenças do aparelho circulatório")
eh_agressao("X954") # true — X85–Y09 + Y87.1 (recorte CVLI)
eh_agressao("Y10") # false — intenção indeterminadaBaixo nível
dcl_descomprime(io, chunk -> processar(chunk)) # descompressor streaming
cabecalho("arquivo.dbc") # só o cabeçalho (campos, larguras)
MicroSUS.limpar_cache() # limpa o cache de downloadCompatibilidade com Tables.jl
Todas as funções de leitura produzem objetos TabelaDBC, que implementam a interface Tables.jl. Ou seja, funcionam direto com DataFrames, Arrow, CSV e qualquer outro consumidor de Tables.jl:
using DataFrames, Arrow
# DataFrame
df = DataFrame(ler(caminho))
# Arrow
Arrow.write("saida.arrow", ler(caminho))
# iterar em lotes
for lote in Tables.partitions(ler(caminho))
# `lote` é um NamedTuple de vetores
endArquitetura do streaming
.dbc ──DCL 4KiB/chunk──▶ registros ──filtro──▶ parse tipado ──▶ lotes
(crus) (sob (só as (NamedTuple,
demanda) colunas Tables.jl)
pedidas)O formato .dbc é um cabeçalho DBF em claro + 4 bytes de CRC + registros comprimidos em PKWare DCL. O descompressor é um porte puro Julia do blast.c de Mark Adler, com a janela de 4 KiB emitida por um callback sink — é isso que permite a leitura com memória constante, qualquer que seja o tamanho do arquivo.
Cada estágio é encadeado por Channels com buffers pequenos: o backpressure é automático. Se o consumidor (seu laço for ou o Arrow.write) desacelera, a descompressão espera. O teto de memória é O(tamanho_lote) — o lote em construção mais um em trânsito — independente do tamanho do arquivo original.
Isenção de responsabilidade
O MicroSUS.jl é uma ferramenta de leitura, não uma fonte de dados. Ele baixa e decodifica arquivos publicados pelo DATASUS/Ministério da Saúde; o conteúdo, a exatidão e a completude desses arquivos são de responsabilidade do órgão que os publica.
- O DATASUS republica bases retroativamente: a mesma consulta em datas diferentes pode devolver números diferentes. Registre a data de extração.
- Dados preliminares existem e são sinalizados por
@warnquando obaixarcai numa pastaPRELIM/. - Os microdados têm defeitos próprios — códigos implausíveis, campos que deixam de ser preenchidos no meio de uma série, layouts que mudam entre anos. Os que conhecemos estão em Exemplos intermediários e no guia de Schemas e tipagem; a lista não é exaustiva.
O software é distribuído como está, sob licença MIT, sem garantia de qualquer espécie e sem responsabilidade por danos decorrentes do uso. Validar os resultados, conferir a plausibilidade dos números e responder pelas conclusões publicadas é de quem faz a análise.
Referência da API
Veja a página Referência da API para a lista completa das funções e tipos exportados, com assinaturas e docstrings. Para detalhes de implementação, veja Internos.