Referência da API

Todos os nomes exportados, organizados por categoria.

MicroSUS.MicroSUS — Module
MicroSUS

Microdados do DATASUS em Julia, com leitura streaming de arquivos .dbc (PKWare DCL) e .dbf: memória constante do arquivo comprimido até o sink, seleção de colunas e filtro de linhas no leitor, transcodificação CP850/Latin-1 → UTF-8, schemas tipados por sistema (SIM, SINASC, SIH, SIA, CNES) e interface Tables.jl com partições.

Uso básico:

using MicroSUS, DataFrames

caminho = baixar(:sim, "PE"; ano = 2023)          # cache local (Scratch.jl)
df = DataFrame(ler(caminho))                       # tudo tipado

# nacional sem estourar RAM: colunas + filtro no leitor
t = ler(caminho; colunas = [:DTOBITO, :CAUSABAS, :CODMUNRES, :IDADE, :SEXO],
        filtro = r -> eh_agressao(r[:CAUSABAS]))   # CVLI: X85–Y09

# streaming direto para Arrow (requer `using Arrow`)
converter(caminho, "do_pe_2023.arrow"; colunas = [:DTOBITO, :CAUSABAS, :CODMUNRES])

Formato .dbc = cabeçalho DBF em claro + 4 bytes de CRC + registros comprimidos com PKWare DCL ("implode"). O descompressor é um porte puro Julia do blast.c de Mark Adler, com janela de 4 KiB emitida em chunks — é isso que permite a leitura em memória constante.

source

Leitura

MicroSUS.ler — Function
ler(caminho; colunas = nothing, filtro = nothing,
    tamanho_lote = 100_000, schema = :auto, encoding = :auto,
    pool = true, ignorar_ausentes = false) -> TabelaDBC

Abre um .dbc ou .dbf do DATASUS como tabela preguiçosa (Tables.jl, com Tables.partitions). Nada é lido até a iteração.

  • colunas: Vector{Symbol} com os campos desejados — os demais nem são materializados. nothing = todos.
  • filtro: função RegistroDBF -> Bool aplicada antes do parse das colunas; r[:CAMPO] devolve o texto do campo sob demanda. Ex.: r -> r[:CODMUNRES] == "261110". haskey(r, :CAMPO) diz se o campo existe neste arquivo — útil em leituras de vários anos, em que r[:LINHAA] daria KeyError nos layouts sem as linhas da DO.
  • schema: :auto (deduz pelo prefixo do arquivo: DO→SIM, DN→SINASC, RD→SIH, PA→SIA, ST→CNES), um Symbol (:sim, ...), um Dict{Symbol,Symbol} próprio, ou nothing (só a tipagem do DBF).
  • encoding: :auto (language driver do cabeçalho; DATASUS ⇒ cp850), ou :cp850, :latin1, :cp1252, :utf8.
  • ignorar_ausentes: quando true, colunas de colunas que não existem no layout deste arquivo são descartadas em vez de lançar ArgumentError. É o que torna prática a leitura multi-ano do SIH, cujo layout ganhou campos em 2011, 2013 e 2014 — sem isso, pedir :DIAGSEC1 derruba a leitura de 2010. As colunas descartadas saem por @debug; se nenhuma das pedidas existir, ainda assim é erro, porque aí o problema é outro (arquivo errado ou nome digitado errado);
  • pool: usa PooledArray nas colunas categóricas do schema (equivalente ao factor do R, opt-in).

Uso: DataFrame(ler(caminho)) materializa tudo; for lote in Tables.partitions(ler(caminho)) processa em lotes; Arrow.write(saida, ler(caminho)) converte em streaming.

source
ler(caminhos::AbstractVector; uniao = false, origem = :ARQUIVO,
    kwargs...) -> TabelaConcatenada

Lê vários arquivos como uma tabela só, em streaming: os lotes saem de um arquivo depois do outro e a memória continua O(tamanho_lote). Os demais kwargs (colunas, filtro, schema, ignorar_ausentes, …) valem para cada arquivo como em ler(caminho).

caminhos = baixar(:sim, "PE"; anos = 2014:2023)
t = ler(caminhos; colunas = [:DTOBITO, :CAUSABAS, :CODMUNRES],
        filtro = r -> eh_agressao(r[:CAUSABAS]))
DataFrame(t)                    # uma linha por óbito, coluna :ARQUIVO = "DOPE2014.dbc", …
Arrow.write("cvli_pe.arrow", t) # um record batch por lote, schema único
  • uniao: com false, todos os arquivos precisam produzir as mesmas colunas — layouts diferentes entre anos são erro, com a lista do que difere. Com true, a saída tem a união das colunas, e as que faltam num arquivo vêm como missing nas linhas dele.
  • origem: nome da coluna acrescentada ao fim com o nome do arquivo de cada linha ("DOPE2023.dbc"); nothing para não acrescentar. Também pode ser uma função caminho -> NamedTuple, que vira uma coluna constante por chave — é assim que fetch_datasus acrescenta UF_ARQUIVO, ANO_ARQUIVO e PRELIMINAR: origem = c -> (ANO = parse(Int, basename(c)[5:8]),).

Os tipos são unificados por coluna: texto de larguras diferentes vira a InlineString mais larga, inteiro e decimal viram Float64, texto e categórico viram categórico. Uma coluna que mude de tipo de outro jeito entre os arquivos (data num ano, texto noutro) vira String em todos, com um aviso.

source
MicroSUS.TabelaDBC — Type
TabelaDBC

Tabela preguiçosa sobre um .dbc/.dbf, criada por ler. Nada é lido do disco até a iteração. Implementa a interface Tables.jl: Tables.partitions produz lotes de tamanho_lote linhas (cada lote é um NamedTuple de vetores) e Tables.columns materializa tudo via materializar — então DataFrame(t), Arrow.write(io, t) e afins funcionam diretamente.

source
MicroSUS.TabelaConcatenada — Type
TabelaConcatenada

Vários .dbc/.dbf lidos como uma tabela preguiçosa só, criada por ler com um vetor de caminhos. Mesma interface Tables.jl de TabelaDBC: Tables.partitions produz os lotes de cada arquivo em sequência, todos com as mesmas colunas e os mesmos tipos, e DataFrame(t) materializa tudo.

source
MicroSUS.materializar — Function
materializar(t::TabelaDBC) -> NamedTuple

Consome todas as partições e concatena as colunas. É o que DataFrame(t) chama por baixo via Tables.columns.

source
materializar(t::TabelaConcatenada) -> NamedTuple

Consome as partições de todos os arquivos e concatena as colunas.

source

Conversão

MicroSUS.converter — Function
converter(entrada, saida; kwargs...)

Converte um .dbc/.dbf para Arrow em streaming (um record batch por lote), sem materializar o arquivo inteiro. Requer using Arrow na sessão (extensão condicional). Aceita os mesmos kwargs de ler.

entrada também pode ser um vetor de caminhos: os arquivos vão para um único .arrow, com schema unificado (ver ler(caminhos::AbstractVector)).

As colunas categóricas são gravadas como texto simples, sem dicionário: o leitor do Arrow.jl falha de forma intermitente em arquivos cujo dicionário cresce de um lote para outro. Por isso converter é o caminho recomendado em vez de Arrow.write(saida, ler(caminho)).

source

Download

MicroSUS.baixar — Function
baixar(sistema, uf; ano = nothing, mes = nothing,
       forcar = false, quieto = false) -> String

Baixa (com cache local via Scratch.jl) um arquivo do DATASUS e devolve o caminho no disco. Chamadas repetidas não rebaixam; forcar = true ignora o cache.

baixar(sistema, uf; anos, meses = nothing) -> Vector{String}

Forma plural: baixa vários períodos em paralelo (asyncmap).

source
MicroSUS.url_arquivo — Function
url_arquivo(sistema, uf; ano = nothing, mes = nothing,
            prelim = false) -> String

URL FTP do arquivo .dbc no DATASUS. Sistemas anuais (:sim, :sinasc) pedem ano; mensais (:sih, :sia, :cnes) pedem ano e mes. prelim = true aponta para a pasta de dados preliminares (anos ainda não consolidados; só :sim e :sinasc).

Ex.: url_arquivo(:sim, "PE"; ano = 2023) → .../SIM/CID10/DORES/DOPE2023.dbc.

source
MicroSUS.baixar_sinan — Function
baixar_sinan(agravo; ano, prelim = false, forcar = false,
             quieto = false) -> String
baixar_sinan(agravo; anos, kwargs...) -> Vector{String}

Baixa (com cache) o arquivo nacional do SINAN de um agravo. Se prelim não for informado e o arquivo FINAIS não existir, tenta automaticamente a pasta PRELIM (com aviso). Forma plural baixa vários anos em paralelo.

source
MicroSUS.url_sinan — Function
url_sinan(agravo; ano, prelim = false) -> String

URL FTP do arquivo NACIONAL do SINAN para um agravo. Os arquivos do SINAN cobrem o Brasil inteiro (DENGBR20.dbc), então não há UF — filtre por residência no ler (SG_UF/ID_MN_RESI). prelim = true aponta para a pasta de dados preliminares.

Agravos: :dengue, :chikungunya, :zika, :meningite, :tuberculose, :hanseniase, :sifilis_congenita, :violencia, … — a lista completa, com o ano inicial de cada um, é agravos_sinan.

Ex.: url_sinan(:dengue; ano = 2020) → .../SINAN/DADOS/FINAIS/DENGBR20.dbc.

source
MicroSUS.agravos_sinan — Function
agravos_sinan() -> Vector{NamedTuple}

Agravos do SINAN disponíveis no pacote: agravo (o símbolo aceito por baixar_sinan e url_sinan), fonte (o identificador em fetch_datasus), prefixo do arquivo nacional (DENG → DENGBR24.dbc), nome e ano_inicial publicado no FTP.

using DataFrames
DataFrame(agravos_sinan())
source
MicroSUS.eh_preliminar — Function
eh_preliminar(caminho) -> Bool

true se o arquivo veio de uma pasta PRELIM/ do DATASUS — dado ainda não consolidado, sujeito a revisão. baixar, baixar_sinan e fetch_datasus guardam esses arquivos em PRELIM/ dentro do cache, separados dos consolidados de mesmo nome.

c = baixar(:sim, "PE"; ano = 2025)
eh_preliminar(c)    # true enquanto o DATASUS não consolidar 2025
source
MicroSUS.limpar_cache — Function
limpar_cache()

Remove todos os .dbc baixados do cache local, inclusive os preliminares (subpasta PRELIM/).

source
MicroSUS.ErroDeRede — Type
MicroSUS.ErroDeRede

Falha ao falar com o servidor — timeout, DNS, conexão recusada, canal de dados do FTP bloqueado —, distinta de "o arquivo não existe". É lançada em vez de seguir com um resultado incompleto. causa é o Downloads.RequestError original.

source
MicroSUS.verificar_cache — Function
verificar_cache(; arquivos = nothing, verbose = true) -> Vector{NamedTuple}

Compara os arquivos do cache com o FTP do DATASUS, sem baixá-los, e diz o que fazer com cada um. A situacao de cada arquivo:

  • :atualizado — o FTP tem o mesmo arquivo (mesmo tamanho);
  • :mudou — o DATASUS republicou o arquivo; baixar(...; forcar = true) ou fetch_datasus(...; cache = false) traz a versão nova;
  • :era_preliminar — o arquivo está no cache como consolidado, mas o consolidado não existe no FTP e o preliminar sim: é um preliminar guardado por versões até a 0.3.1 do pacote, que o tratavam como definitivo. Rebaixe com forcar = true;
  • :consolidado_disponivel — preliminar no cache, e o DATASUS já publicou o consolidado; o próximo fetch_datasus passa a usá-lo;
  • :ausente_no_ftp — nenhuma URL candidata existe mais no servidor;
  • :sem_url — o nome não corresponde a nenhuma fonte do catálogo;
  • :sem_resposta — o servidor não respondeu (cada consulta é tentada três vezes); a verificação desse arquivo fica por fazer.

Colunas: arquivo, situacao, bytes_cache, bytes_ftp, url, baixado_em (do registro de origem; para arquivos baixados antes desta versão, a data do arquivo). arquivos restringe a verificação (vetor de nomes ou Regex, como r"^DOPE"). Consulta dois arquivos por vez pelo canal de controle do FTP, que responde mesmo onde o firewall bloqueia as transferências.

A comparação é por tamanho: uma republicação que mantenha exatamente o mesmo número de bytes passa como :atualizado. O FTP do DATASUS não informa a data de modificação por esta via.

v = DataFrame(verificar_cache())
filter(r -> r.situacao in (:mudou, :era_preliminar), v)
source
MicroSUS.proveniencia — Function
proveniencia(df) -> Vector{NamedTuple}

Os arquivos de que um resultado de fetch_datasus veio: arquivo, url, baixado_em, bytes, sha256 e preliminar. É o que uma nota de método precisa para que a análise possa ser refeita sobre os mesmos dados — o DATASUS republica bases retroativamente, e a URL sozinha não identifica a versão. Acompanha o DataFrame em cópias e recortes (metadado de estilo :note).

df = fetch_datasus(:SIM_DO; uf = "PE", anos = 2019:2023)
DataFrame(proveniencia(df))

Para arquivos baixados antes da 0.4.1, sem registro de origem, baixado_em é a data do arquivo no cache e o SHA-256 é calculado na primeira vez.

source
MicroSUS.exportar_espelho — Function
exportar_espelho(destino; arquivos = nothing) -> Vector{String}

Copia os arquivos do cache para destino, na árvore de pastas do FTP do DATASUS (destino/SIM/CID10/DORES/DOPE2023.dbc), e devolve os caminhos criados. A pasta pode então servir de espelho para outras pessoas — numa rede compartilhada (file://), num bucket ou num servidor HTTP —, via MICROSUS_ESPELHOS:

exportar_espelho("/mnt/grupo/datasus")                 # quem tem os arquivos
ENV["MICROSUS_ESPELHOS"] = "file:///mnt/grupo/datasus" # quem não alcança o FTP
fetch_datasus(:SIM_DO; uf = "PE", anos = 2023)

Por padrão, um espelho só é usado quando o FTP do DATASUS falha por rede; MICROSUS_ESPELHO_PRIMEIRO=true o põe na frente. O DATASUS continua decidindo se um arquivo existe, e o registro de origem de cada download diz se ele veio de um espelho (obtido_de em proveniencia). Um espelho não é verificado contra o DATASUS: o SHA-256 em proveniencia é o que permite conferir que os bytes são os mesmos de quem os baixou — e restaurar_dados faz essa conferência.

arquivos restringe a cópia (nomes, ou um Regex), como em verificar_cache. Arquivos cuja URL de origem não se conhece ficam de fora.

source
MicroSUS.travar_dados — Function
travar_dados(arquivo, resultados...) -> Vector{NamedTuple}

Grava em arquivo (TOML) de quais arquivos do DATASUS vieram os resultados — DataFrames de fetch_datasus, ou o que proveniencia devolve: nome, URL, SHA-256, tamanho, data da extração, se era preliminar e, se veio de um espelho, de onde. É o Manifest.toml dos dados: versione-o junto com o script.

df  = fetch_datasus(:SIM_DO; uf = "PE", anos = 2019:2023)
pop = fetch_datasus(:SINASC; uf = "PE", anos = 2019:2023)
travar_dados("dados.toml", df, pop)

# meses depois, ou em outra máquina:
restaurar_dados("dados.toml")
df = fetch_datasus(:SIM_DO; uf = "PE", anos = 2019:2023)   # os mesmos bytes

Ver restaurar_dados.

source
MicroSUS.restaurar_dados — Function
restaurar_dados(arquivo = "dados.toml"; estrito = true, ativar = true)
    -> Vector{NamedTuple}

Devolve ao cache os arquivos de um manifest de travar_dados, conferindo cada um pelo SHA-256, e ativa a trava na sessão. Para cada arquivo, a situacao:

  • :no_cache — já estava no cache com o mesmo hash; nada foi baixado;
  • :restaurado — baixado de origem (o DATASUS ou um espelho de MICROSUS_ESPELHOS) com o mesmo hash;
  • :diferente — o arquivo existe, mas nenhuma origem tem os mesmos bytes: o DATASUS o republicou e nenhum espelho guardou a versão travada (sha256_obtido é o hash do que existe hoje);
  • :indisponivel — nenhuma origem respondeu com o arquivo.

O DATASUS não guarda versões antigas: a versão travada de um arquivo republicado só volta de um espelho que a tenha (ver exportar_espelho), ou não volta. Com estrito = true (padrão), qualquer arquivo que não volte com o mesmo hash é erro — a análise não roda sobre outros dados sem que você decida. Com estrito = false, a versão atual do DATASUS entra no cache no lugar e a lista diz quais mudaram.

Com a trava ativa, um arquivo travado vem sempre do cache — fetch_datasus, baixar e baixar_sinan não o buscam no FTP, nem trocam o preliminar travado pelo consolidado — e a proveniencia traz a data da extração original. soltar_dados desativa.

source
MicroSUS.baixar_url — Function
baixar_url(url; cache = true, verbose = true) -> Union{String,Nothing}

Baixa url para o cache local e devolve o caminho do arquivo, ou nothing se o arquivo não existir no servidor. Erros de rede (timeout, DNS, conexão recusada) viram MicroSUS.ErroDeRede; só a ausência do arquivo é nothing, porque a existência de partições (PA...b.dbc) e de arquivos preliminares só pode ser descoberta tentando.

source

Fetch (interface de alto nível)

MicroSUS.fetch_datasus — Function
fetch_datasus(fonte::Symbol; uf = :all, anos, meses = nothing,
              colunas = nothing, filtro = nothing,
              processar = true, cache = true, verbose = true) -> DataFrame

Baixa, descomprime, lê e concatena microdados públicos do DATASUS.

Argumentos

  • fonte: identificador da fonte — ver fontes. Ex.: :SIM_DO, :SINASC, :SIH_RD, :SIA_PA, :CNES_ST, :SINAN_DENGUE;
  • uf: sigla ("PE"), vetor de siglas (["PE", "BA"]) ou :all para as 27 unidades federativas. Ignorado em fontes de abrangência nacional (SINAN);
  • anos: ano (2023) ou coleção de anos (2019:2023);
  • meses: mês ou coleção de meses (1:12), obrigatório apenas para fontes mensais (SIH, SIA, CNES);
  • colunas: Vector{Symbol} com os campos desejados, como em ler — os demais nem são lidos. Campos que não existem no layout de algum ano vêm missing nas linhas dele;
  • filtro: função RegistroDBF -> Bool aplicada a cada registro antes do parse, como em ler. Vê os códigos crus do arquivo (r[:SEXO] == "2"), não os rótulos da padronização;
  • processar: aplica a padronização da fonte quando disponível (process_sim, process_sinasc);
  • cache: reutiliza arquivos já baixados (ver MicroSUS.limpar_cache);
  • verbose: registra progresso via @info/@warn.

Os arquivos são lidos em streaming, um depois do outro (ver ler(caminhos::AbstractVector)), e a padronização roda no próprio resultado, sem cópia: o pico de memória fica perto do tamanho do DataFrame devolvido. Com colunas e filtro, só o que foi pedido chega a existir. Até 4 arquivos são baixados ao mesmo tempo, e com mais de uma thread (julia -t auto) vários são lidos em paralelo; a ordem das linhas não muda.

Arquivos ausentes no FTP (ano ainda não publicado para uma UF, mês sem partição extra) geram um @warn e são pulados; o resultado concatena tudo que foi encontrado, unindo colunas por nome. As colunas UF_ARQUIVO, ANO_ARQUIVO e, se aplicável, MES_ARQUIVO identificam a origem de cada linha, e PRELIMINAR diz se ela veio de um arquivo ainda não consolidado pelo DATASUS (pasta PRELIM/, ver eh_preliminar) — quando houver algum, um @warn lista quais.

Exemplos

# Óbitos de Pernambuco, 2019–2023, já padronizados
do_pe = fetch_datasus(:SIM_DO; uf = "PE", anos = 2019:2023)

# Nascidos vivos, PE e BA, sem padronização (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)

# Só o que interessa: óbitos por agressão em PE, três colunas, dez anos
cvli = fetch_datasus(:SIM_DO; uf = "PE", anos = 2014:2023,
                     colunas = [:DTOBITO, :CAUSABAS, :CODMUNRES],
                     filtro = r -> eh_agressao(r[:CAUSABAS]))
source
MicroSUS.fontes — Function
fontes() -> Vector{NamedTuple}

Lista as fontes de microdados disponíveis no pacote, com identificador, descrição, periodicidade, abrangência e faixa de anos (ano_final é missing para fontes ainda publicadas).

Exemplo

using MicroSUS, DataFrames
DataFrame(fontes())
source
MicroSUS.fonte — Function
fonte(id::Symbol) -> FonteDATASUS

Devolve a especificação registrada da fonte id (ver fontes para a lista de identificadores disponíveis). Lança ArgumentError para um identificador desconhecido.

source
MicroSUS.process_sim — Function
process_sim(df::DataFrame; copiar = true) -> DataFrame

Padroniza microdados do SIM (:SIM_DO): converte datas (DTOBITO, DTNASC, ...) para Date, rotula variáveis categóricas (sexo, raça/cor, estado civil, escolaridade, local de ocorrência, circunstância do óbito etc.) e cria IDADE_ANOS a partir do campo codificado IDADE.

Colunas ausentes no layout do ano são simplesmente ignoradas; a coluna original IDADE é preservada. Chamado automaticamente por fetch_datasus quando processar = true.

copiar = false padroniza df no lugar, sem a cópia inicial — o que fetch_datasus faz, já que o DataFrame é dele.

source
MicroSUS.process_sinasc — Function
process_sinasc(df::DataFrame; copiar = true) -> DataFrame

Padroniza microdados do SINASC (:SINASC): converte datas (DTNASC, DTNASCMAE, ...) para Date, rotula variáveis categóricas (sexo, tipo de parto, gravidez, escolaridade e estado civil da mãe, raça/cor, consultas de pré-natal, local de nascimento) e converte numéricos armazenados como texto (PESO, IDADEMAE, APGAR1, APGAR5, SEMAGESTAC, ...).

Colunas ausentes no layout do ano são ignoradas. Chamado automaticamente por fetch_datasus quando processar = true.

copiar = false padroniza df no lugar, sem a cópia inicial — o que fetch_datasus faz, já que o DataFrame é dele.

source
MicroSUS.process_sih — Function
process_sih(df::DataFrame; copiar = true) -> DataFrame

Padroniza microdados do SIH/SUS (:SIH_RD): rotula as variáveis categóricas de domínio fechado (SEXO, RACA_COR, IDENT, CAR_INT, MORTE) e cria IDADE_ANOS a partir de IDADE + COD_IDADE.

Colunas ausentes no layout do ano são ignoradas — o layout do SIH mudou em 2011, 2013 e 2014, e a rotina é escrita para sobreviver a isso. As colunas originais são preservadas.

O que esta rotina deliberadamente não rotula

COBRANCA (motivo de saída) e ESPEC (especialidade do leito) têm domínios extensos que variam entre versões da tabela da AIH. Como rotular! converte código não mapeado em missing, um dicionário incompleto apagaria dados válidos em silêncio — pior que devolver o código cru. Ficam como estão; use as tabelas oficiais da AIH se precisar deles rotulados.

RACA_COR = "99" (sem informação) vira missing, que é o que ele significa.

Chamada automaticamente por fetch_datasus quando processar = true.

copiar = false padroniza df no lugar, sem a cópia inicial — o que fetch_datasus faz, já que o DataFrame é dele.

source
MicroSUS.process_sinan — Function
process_sinan(df::DataFrame; agravo = :auto, copiar = true) -> DataFrame

Padroniza microdados do SINAN. Rotula o núcleo comum às fichas de todos os agravos — TP_NOT, CS_SEXO, CS_RACA, CS_GESTANT, CS_ESCOL_N, HOSPITALIZ — e cria IDADE_ANOS (anos completos) a partir de NU_IDADE_N.

CLASSI_FIN, CRITERIO e EVOLUCAO mudam de significado entre agravos e só são rotulados quando o agravo é conhecido: agravo pode ser :dengue, :chikungunya, :zika ou nothing (só o núcleo). Com :auto, o agravo é inferido de ID_AGRAVO quando todas as linhas apontam para um dos três; nos demais (malária, tuberculose, violência…) esses campos ficam como estão.

Códigos com zero à esquerda ("01") valem o mesmo que sem ("1") — os arquivos trazem as duas formas. Códigos de "ignorado" ("9", "I") e não documentados ("0" em CLASSI_FIN) viram missing.

Colunas ausentes são ignoradas e as originais, preservadas. Chamado automaticamente por fetch_datasus quando processar = true, com o agravo da fonte (:SINAN_DENGUE → :dengue).

Fichas anteriores ao SINAN NET

Os dicionários do núcleo são os do SINAN NET (2007 em diante). Arquivos mais antigos usam outras codificações em alguns campos — TUBEBR01 traz CS_RACA = "0" em 83% dos registros, campo que a ficha da época não coletava. Rotular esses anos exige o dicionário da ficha correspondente.

copiar = false padroniza df no lugar, sem a cópia inicial — o que fetch_datasus faz, já que o DataFrame é dele.

source
MicroSUS.process_cnes — Function
process_cnes(df::DataFrame; copiar = true) -> DataFrame

Padroniza microdados do CNES — estabelecimentos (:CNES_ST) e profissionais (:CNES_PF): rotula os campos categóricos presentes (tipo de unidade TP_UNID, esfera administrativa ESFERA_A, natureza NATUREZA/NAT_JUR, nível de hierarquia NIV_HIER, tipo de gestão TPGESTAO, vínculo com o SUS VINC_SUS, turno TURNO_AT, clientela CLIENTEL, os indicadores sim/não de serviços, e mais — 119 campos ao todo). Códigos com e sem zero à esquerda valem o mesmo.

Os dicionários vêm do microdatasus (licença MIT, ver data/LICENSE-microdatasus) e só incluem campos cujos códigos observados em arquivos reais estão todos cobertos. Um código fora do dicionário — que pode aparecer em anos ou UFs não verificados — vira missing com um @warn que diz qual é e em quantos registros.

copiar = false padroniza df no lugar. Chamado automaticamente por fetch_datasus para :CNES_ST e :CNES_PF.

Não verificado

Os rótulos não foram conferidos contra as tabelas oficiais do DATASUS (TAB_CNES), indisponíveis no momento da escrita. Em NIV_HIER, os códigos 3 e 6 têm o mesmo rótulo ("Média M2 e M3") no dicionário de origem.

source

Qualidade dos dados

MicroSUS.auditar — Function
auditar(df; ano = nothing, limiar = 20) -> MicroSUS.Auditoria

Checagens de qualidade de um resultado de fetch_datasus (ou de ler) — o que olhar antes de analisar. Mostra um resumo; os detalhes ficam nos campos de MicroSUS.Auditoria.

df = fetch_datasus(:SIM_DO; uf = "PE", anos = 2014:2023)
a = auditar(df)
a.descontinuidades                 # campos que pararam (ou começaram) a ser preenchidos
a.causas                           # % de causas mal definidas por ano
filter(r -> r.ano == 2023, a.completude)
  • Completude por coluna e ano. Ausente é missing ou texto vazio. Os códigos de "ignorado" (9, 0…) só contam como ausência nos dados padronizados (processar = true, o padrão), onde viram missing; nos brutos, são um código como outro.
  • Descontinuidades: o preenchimento muda limiar pontos percentuais (padrão 20) ou mais entre um ano e o seguinte — um campo que deixa de existir no layout aparece aqui como queda para 0%. Anos com menos de 10% dos registros do maior (as notificações de 2024 dentro do arquivo do SINAN de 2023) ficam fora da comparação.
  • Causas básicas (SIM): mal definidas (R00–R99) e códigos que a CID-10 marca como não utilizáveis como causa básica — medidas clássicas da qualidade da declaração de óbito (cid10) —, e códigos que nem estão na CID-10.
  • Valores implausíveis: idade acima de 120 anos ou negativa, datas de evento no futuro ou antes de 1900 (de nascimento, só no futuro), nascimento depois do óbito, peso fora de 100–7.000 g, idade da mãe fora de 10–60, semanas de gestação fora de 20–45 (o 99 de "ignorado" não conta), causa básica incompatível com o sexo. São marcas para revisar, não erros certos: exemplos traz as primeiras linhas de cada regra.

O ano vem de ano (uma coluna), de ANO_ARQUIVO ou da primeira data de evento tipada (DTOBITO, DTNASC, DT_NOTIFIC…); ano = false audita tudo junto.

source
MicroSUS.Auditoria — Type

Resultado de auditar. Cada campo é um DataFrame:

  • completude — por coluna e ano: n, preenchidos, pct_preenchido;
  • descontinuidades — colunas cujo preenchimento muda de um ano para o seguinte em limiar pontos percentuais ou mais (campo que parou ou começou a ser preenchido, ou mudança de layout);
  • causas — por ano, só com CAUSABAS (SIM): causas mal definidas (capítulo XVIII, R00–R99), códigos que não valem como causa básica e códigos fora da CID-10;
  • implausiveis — por regra: quantos registros, a fração e alguns exemplos.
source

Decodificação de schemas

MicroSUS.decodifica_idade_sim — Function
decodifica_idade_sim(s) -> Union{Missing,Float64}

Idade do SIM (campo IDADE, 3 dígitos: 1º = unidade, 2º–3º = valor) convertida para anos:

1º dígitounidade
0minutos
1horas
2dias
3meses
4anos (0–99)
5100 + valor
9ignorada

Ex.: "425" → 25.0; "501" → 101.0; "310" → 10/12; "999" → missing.

source
MicroSUS.decodifica_idade_sinan — Function
decodifica_idade_sinan(s) -> Union{Missing,Float64}

Idade do SINAN (campo NU_IDADE_N, 4 dígitos: 1º = unidade, 3º–4º = valor 0–99) convertida para anos. Mesma escala de unidades do SIM, mas com 4 dígitos: "4025" → 25.0; "3006" → 0.5 (6 meses); "2015" → 15/365.25 (15 dias); "5010" → 110.0; "999"/inválido → missing.

source
MicroSUS.idade_sih — Function
idade_sih(idade, cod_idade) -> Union{Int,Missing}

Idade em anos completos a partir do par IDADE + COD_IDADE do SIH. O COD_IDADE é a unidade: 0 minutos, 1 horas, 2 dias, 3 meses, 4 anos, 5 anos acima de 100 (IDADE = 5, COD_IDADE = 5 ⇒ 105 anos). Idades abaixo de um ano resultam em 0.

Diferente do SIM, onde unidade e valor vêm no mesmo campo de 3 dígitos (decodifica_idade_sim), aqui são duas colunas — por isso a função recebe dois argumentos.

Aceita tanto os valores já tipados pelo schema quanto o texto cru.

source
MicroSUS.SCHEMAS — Constant
SCHEMAS :: Dict{Symbol,Dict{Symbol,Symbol}}

Registro de schemas por sistema (:sim, :sinasc, :sih, :sia, :cnes): campo → tipo lógico (:texto, :pool, :inteiro, :float, :data_ddmmyyyy, :data_yyyymmdd, :idade_sim). Campos ausentes caem na tipagem do DBF. Mutável de propósito — dá para estender em runtime: MicroSUS.SCHEMAS[:sim][:OCUP] = :texto.

source
MicroSUS.detecta_sistema — Function
detecta_sistema(caminho) -> Union{Nothing,Symbol}

Deduz o sistema pelo prefixo do nome do arquivo (DOPE2023.dbc → :sim, DNPE2023.dbc → :sinasc, RDPE2301.dbc → :sih, ...).

source

Indicadores

MicroSUS.mortalidade_infantil — Function
mortalidade_infantil(obitos, nascidos; nivel = :uf) -> DataFrame

Taxa de mortalidade infantil e seus componentes (RIPSA C.1 a C.1.3), por 1.000 nascidos vivos, por território de residência e ano:

  • obitos_infantis / taxa — óbitos de menores de 1 ano;
  • neonatal_precoce / taxa_neonatal_precoce — 0 a 6 dias;
  • neonatal_tardia / taxa_neonatal_tardia — 7 a 27 dias;
  • pos_neonatal / taxa_pos_neonatal — 28 dias a menos de 1 ano.

obitos vem do SIM (fetch_datasus(:SIM_DO, …) ou :SIM_DOINF) e nascidos do SINASC (fetch_datasus(:SINASC, …)), com as mesmas UFs e anos. nivel: :brasil, :uf, :municipio, :regiao_saude, :macrorregiao_saude, :regiao_imediata ou :regiao_intermediaria.

do_ = fetch_datasus(:SIM_DO; uf = "PE", anos = 2022)
dn  = fetch_datasus(:SINASC; uf = "PE", anos = 2022)
mortalidade_infantil(do_, dn; nivel = :regiao_saude)

Método direto, sem os fatores de correção de sub-registro que o Ministério da Saúde aplica onde a cobertura do SIM e do SINASC é incompleta (parte do Norte e do Nordeste): ali a taxa fica abaixo da oficial. Óbitos com idade ignorada ficam fora. Em município pequeno a taxa oscila muito de um ano para o outro — a RIPSA recomenda agregar anos ou usar nível maior.

source
MicroSUS.razao_mortalidade_materna — Function
razao_mortalidade_materna(obitos, nascidos; nivel = :uf) -> DataFrame

Razão de mortalidade materna (RIPSA C.3): óbitos maternos por 100.000 nascidos vivos, por território de residência e ano. Óbito materno é o de causa básica em O00–O95, O98–O99 ou A34 (tétano obstétrico) — o capítulo XV da CID-10 sem as mortes maternas tardias e as sequelas (O96, O97).

razao_mortalidade_materna(do_, dn; nivel = :uf)

Como na mortalidade_infantil: método direto, sem fatores de correção — o Ministério da Saúde corrige a RMM pelo sub-registro e pela má classificação das causas, e a razão oficial costuma ficar acima desta. A RIPSA inclui ainda, sob condições (morte durante a gravidez ou o puerpério), F53, M83.0, D39.2, E23.0 e B20–B24; elas não entram aqui. Com poucos óbitos por território, a razão é instável: agregue anos.

source
MicroSUS.proporcao_mal_definidas — Function
proporcao_mal_definidas(obitos; nivel = :uf) -> DataFrame

Proporção de óbitos por causas mal definidas: causa básica no capítulo XVIII da CID-10 (R00–R99), em % do total de óbitos, por território de residência e ano. É a medida mais usada da qualidade da declaração da causa de morte: onde ela é alta, qualquer análise por causa subestima as causas de fato. auditar mostra, além disso, os códigos que não valem como causa básica.

source
MicroSUS.mortalidade_prematura_dcnt — Function
mortalidade_prematura_dcnt(obitos; nivel = :uf, populacao = nothing) -> DataFrame

Taxa de mortalidade prematura (30 a 69 anos) pelas quatro principais doenças crônicas não transmissíveis — circulatórias (I00–I99), neoplasias (C00–C97), respiratórias crônicas (J30–J98) e diabetes (E10–E14) —, por 100.000 habitantes de 30 a 69 anos: o indicador do Plano de DANT 2021–2030 e da meta 3.4 dos ODS. Por território de residência e ano.

O denominador vem de populacao_por_idade (SIDRA, com cache): Censos de 2010 e 2022 em qualquer nível; nos demais anos, a projeção do IBGE, só para :uf e :brasil. populacao aceita uma tabela pronta, com a coluna de território do nivel (codigo_uf, codigo6, codigo_regiao_saude…), ano e populacao (já de 30 a 69 anos).

Taxa bruta, como no Plano de DANT; para comparar lugares com estruturas etárias diferentes, padronize (taxa_padronizada).

source

Dimensões

MicroSUS.dv_ibge — Function
dv_ibge(cod6) -> Int

Dígito verificador do código de município IBGE (algoritmo módulo 10 com pesos alternados 1,2 e redução de produtos ≥ 10). Aceita Integer ou string de 6 dígitos. Ex.: dv_ibge(261110) == 1 (Petrolina → 2611101).

source
MicroSUS.codigo7_ibge — Function
codigo7_ibge(cod6) -> Int

Código de 7 dígitos a partir do de 6 (SIM/SINASC usam 6; IBGE moderno usa 7). codigo7_ibge(261110) == 2611101. O dígito verificador vem da tabela oficial (municipios) — nove municípios fogem do algoritmo de dv_ibge — e do algoritmo para códigos fora dela.

source
MicroSUS.codigo6_ibge — Function
codigo6_ibge(cod7; validar = true) -> Int

Código de 6 dígitos a partir do de 7, opcionalmente validando o dígito verificador (contra a tabela oficial, como em codigo7_ibge).

source
MicroSUS.uf_de — Function
uf_de(cod) -> Union{String,Missing}

Sigla da UF de um código IBGE — município de 6 ou 7 dígitos, ou o próprio código de 2 dígitos da UF. uf_de("261160") == "PE", uf_de(53) == "DF". Código vazio, não numérico ou de UF inexistente dá missing.

source
MicroSUS.regiao — Function
regiao(x) -> Union{String,Missing}

Grande região ("Norte", "Nordeste", "Sudeste", "Sul", "Centro-Oeste") a partir da sigla da UF (regiao("PE")) ou de um código IBGE de UF ou município (regiao(2611606)). Desconhecido dá missing.

source
MicroSUS.municipio — Function
municipio(cod) -> Union{NamedTuple,Nothing}

Município do código IBGE cod, de 6 dígitos (como no SIM, SINASC e SIH) ou de 7 (com dígito verificador), inteiro ou texto:

m = municipio("261160")   # (codigo7 = 2611606, codigo6 = 261160, nome = "Recife",
                         #  uf = "PE", regiao = "Nordeste", …)
m.regiao_saude           # "I Região de Saúde"
m.regiao_imediata        # "Recife"

Devolve nothing para código vazio, ignorado ou fora da tabela (ver municipios). Um código de 7 dígitos com dígito verificador errado também dá nothing.

source
MicroSUS.municipios — Function
municipios() -> Vector{NamedTuple}

Tabela dos municípios brasileiros embarcada no pacote (IBGE, 5.571 linhas contando Brasília e Fernando de Noronha), sem acesso à rede: colunas codigo7, codigo6, nome, uf, regiao e as divisões abaixo da UF, cada uma com código e nome:

  • codigo_regiao_saude, regiao_saude — a região de saúde (CIR) do SUS, onde se pactua a rede de atenção (439, com o Distrito Federal como uma só);
  • codigo_macrorregiao_saude, macrorregiao_saude — a macrorregião de saúde, que agrupa regiões de saúde (121);
  • codigo_regiao_imediata, regiao_imediata e codigo_regiao_intermediaria, regiao_intermediaria — a divisão regional do IBGE de 2017 (510 e 133), que substituiu micro e mesorregiões.

Nomes se repetem entre UFs (há região de saúde "Norte" e "Central" em várias, e região imediata "Valença" na BA e no RJ): agrupe pelo código. É uma tabela Tables.jl — DataFrame(municipios()) — pronta para leftjoin com codigo6 contra CODMUNRES (SIM, SINASC) ou MUNIC_RES (SIH) convertidos para inteiro:

mun = DataFrame(municipios())
df.codigo6 = parse.(Int, df.CODMUNRES)
leftjoin!(df, mun[:, [:codigo6, :codigo_regiao_saude, :regiao_saude]]; on = :codigo6)
obitos = combine(groupby(df, [:codigo_regiao_saude, :regiao_saude]), nrow => :obitos)

e populacao dá o denominador no mesmo nível (nivel = :regiao_saude).

Fontes: IBGE (API de localidades) para nomes e regiões geográficas; DATASUS (as tabelas territoriais do TabNet) para regiões e macrorregiões de saúde, que mudam por pactuação nas CIBs — a tabela é a de outubro de 2026.

Reflete a divisão territorial atual: municípios extintos ou desmembrados em anos antigos, e os códigos "ignorado" do DATASUS ("260000", "000000"), não estão nela.

source
MicroSUS.capitulo_cid10 — Function
capitulo_cid10(cod) -> Union{Nothing,NamedTuple}

Capítulo CID-10 de um código como "X954" ou "I219": (numeral = "XX", nome = "Causas externas ..."), ou nothing se o código for inválido/vazio.

source
MicroSUS.cid10 — Function
cid10(cod) -> Union{NamedTuple,Nothing}

O registro da CID-10 de cod ("I219", "I21.9", "I21", "I10X"):

  • codigo, descricao — do código pedido ou, se ele não está na tabela, da sua categoria;
  • nivel — :subcategoria, :categoria, ou :categoria_da_subcategoria quando o código é posterior à tabela e a descrição veio do nível acima;
  • categoria, descricao_categoria, grupo (o agrupamento, como "Doenças isquêmicas do coração"), capitulo (algarismo romano);
  • sexo — 'M'/'F' para códigos restritos a um sexo, missing se não;
  • causa_basica_valida — false para os 1.291 códigos que a tabela marca como não utilizáveis como causa básica de óbito (úteis para medir a qualidade da declaração);
  • origem — "DATASUS 2008" ou, para a dengue (A97), o suplemento da OMS de 2016.

nothing para código vazio ou desconhecido.

cid10("I21.9").descricao          # "Infarto agudo do miocárdio não especificado"
cid10("I21.9").grupo              # "Doenças isquêmicas do coração"
cid10("R99").causa_basica_valida  # true — mas veja `capitulo`: XVIII, mal definidas

A tabela é a última publicada pelo DATASUS em CSV (versão 2008). Códigos criados depois caem na descrição da categoria; ver descricao_cid.

source
MicroSUS.descricao_cid — Function
descricao_cid(cod) -> Union{String,Missing}

A descrição em português de um código da CID-10, para rotular tabelas: descricao_cid.(df.CAUSABAS). Códigos posteriores à tabela de 2008 do DATASUS recebem a descrição da categoria (ver cid10, campo nivel); código vazio ou desconhecido dá missing.

source
MicroSUS.normaliza_cid — Function
normaliza_cid(cid) -> String

Forma canônica de um código CID-10: maiúsculas, sem ponto, espaço, * ou -. normaliza_cid(" a81.0 ") == "A810"; missing vira "".

source
MicroSUS.cid_casa — Function
cid_casa(cid, alvos) -> Bool

true se o código cid (um campo como CAUSABAS ou DIAG_PRINC) cai em algum dos alvos. Cada alvo é um prefixo ("A81" pega A81.0–A81.9; "A810" só A81.0) ou uma faixa inclusiva de categorias ("X85" => "Y09"). O código é normalizado antes (normaliza_cid); missing e vazio dão false.

Feito para o filtro de ler:

dcj = ["A810", "F021"]
ler(caminho; filtro = r -> cid_casa(r[:CAUSABAS], dcj))
source
MicroSUS.cids_em — Function
cids_em(texto) -> Vector{String}

Códigos CID-10 contidos num campo de texto livre com vários códigos, como as linhas da Declaração de Óbito do SIM (LINHAA…LINHAD, LINHAII), onde vêm concatenados: cids_em("*I219*E149") == ["I219", "E149"].

source
MicroSUS.menciona_cid — Function
menciona_cid(texto, alvos) -> Bool

true se algum código de cids_em(texto) casa com alvos (mesmas regras de cid_casa). Serve para causas múltiplas: um óbito em que a doença aparece na cadeia de causas, mas não como causa básica.

linhas = (:LINHAA, :LINHAB, :LINHAC, :LINHAD, :LINHAII)
ler(caminho; colunas = [:CAUSABAS, linhas...],
    filtro = r -> cid_casa(r[:CAUSABAS], dcj) ||
                  any(l -> menciona_cid(r[l], dcj), linhas))

Os códigos são separados um a um antes de comparar: um alvo nunca casa com um pedaço formado pela junção de dois códigos vizinhos.

source
MicroSUS.eh_agressao — Function
eh_agressao(cid) -> Bool

true se a causa básica é agressão (homicídio): X85–Y09, mais Y87.1 (sequelas de agressões) — o recorte usual de CVLI a partir do SIM. Equivale a cid_casa(cid, ("X85" => "Y09", "Y871")).

source
MicroSUS.populacao — Function
populacao(anos; nivel = :municipio, interpolar = false, cache = true)
    -> Vector{NamedTuple}

População residente do IBGE, por município (nivel = :municipio), UF (:uf) ou Brasil (:brasil), para um ano ou coleção de anos — o denominador para transformar contagens em taxas. Vem da API SIDRA na primeira chamada e fica em cache local.

Colunas: codigo7 e codigo6 (município; o de 6 dígitos casa com CODMUNRES do SIM/SINASC e MUNIC_RES do SIH) ou codigo_uf (UF), mais nome, ano, populacao e fonte. É uma tabela Tables.jl: DataFrame(populacao(2019:2021)).

Também por região de saúde (:regiao_saude), macrorregião de saúde (:macrorregiao_saude) e regiões imediata e intermediária do IBGE (:regiao_imediata, :regiao_intermediaria), somando os municípios pela tabela de municipios: a coluna de código tem o mesmo nome que lá (codigo_regiao_saude…), para o join, e vem com nome e uf. A composição das regiões é a atual em qualquer ano pedido.

pop = DataFrame(populacao(2021))
obitos = combine(groupby(df, :CODMUNRES), nrow => :obitos)
obitos.codigo6 = parse.(Int, obitos.CODMUNRES)
t = innerjoin(obitos, pop; on = :codigo6)
t.taxa = 100_000 .* t.obitos ./ t.populacao

A série não é homogênea

Cada ano vem da fonte que o IBGE publicou para ele, registrada na coluna fonte: Censo (2000, 2010, 2022), Contagem (2007) ou estimativa anual (os demais). As estimativas de 2011–2021 superestimaram a população — o Censo 2022 achou 203,1 milhões contra 213,3 milhões estimados para 2021, e −10,4% em Recife —, então uma taxa calculada com elas cai artificialmente de 2021 para 2022 sem que nada tenha mudado no numerador. Séries longas pedem retroprojeção (que o IBGE ainda não publicou para os municípios) ou, no mínimo, uma nota.

2023

O IBGE não publicou população para 2023. Com interpolar = false (padrão) pedir 2023 é erro; com true, sai a interpolação geométrica entre os anos publicados vizinhos (Censo 2022 e estimativa 2024), com a fonte dizendo isso. Atenção: a estimativa de 2024 não está na mesma base que o Censo 2022 (Brasil: 203,1 → 212,6 milhões em dois anos), e a interpolação herda a diferença.

Anos antes de 2000 não estão disponíveis. cache = false consulta a SIDRA de novo (o IBGE revisa estimativas de tempos em tempos).

source
MicroSUS.populacao_por_idade — Function
populacao_por_idade(ano; nivel = :uf, largura = 5, aberta = 80, cache = true)
    -> Vector{NamedTuple}

População residente do IBGE por sexo e faixa etária — o denominador das taxas específicas por idade e da padronização (ver taxa_padronizada).

anonívelfonte
2010, 2022:municipio, :uf, :brasil e os regionaisCenso
demais, 2000–2060:uf, :brasilprojeção da população, revisão 2018

Os níveis regionais — :regiao_saude, :macrorregiao_saude, :regiao_imediata, :regiao_intermediaria — somam os municípios, como em populacao, e por isso só existem nos anos de Censo.

Colunas: o código do território (codigo7/codigo6, codigo_uf, codigo_regiao_saude e afins com uf, ou nenhum), nome, ano, sexo ("Masculino"/"Feminino"), faixa ("0 a 4 anos" … "80 anos ou mais", como em faixa_etaria), idade_min, populacao e fonte.

A projeção é anterior ao Censo 2022

Fora dos anos de Censo, os números vêm da projeção do IBGE revista em 2018, que superestima a população como as estimativas de 2011–2021 (Brasil: 213,3 milhões projetados para 2021 contra 203,1 milhões recenseados em 2022). Para padronizar — onde importam as proporções entre faixas — o efeito é menor que para contar habitantes; a coluna fonte registra de onde veio cada número.

largura e aberta definem as faixas; aberta não pode passar do grupo aberto da fonte (90 na projeção, 100 nos Censos). A consulta à SIDRA é por idade simples e fica em cache; no nível municipal, uma UF por vez.

source
MicroSUS.faixa_etaria — Function
faixa_etaria(idade; largura = 5, aberta = 80) -> Union{String,Missing}

Faixa etária de uma idade em anos completos, no formato de populacao_por_idade: "0 a 4 anos", "5 a 9 anos", …, "80 anos ou mais". Use as mesmas largura e aberta dos dois lados para que o numerador (os casos) e o denominador (a população) casem.

faixa_etaria(37)                  # "35 a 39 anos"
faixa_etaria(91)                  # "80 anos ou mais"
faixa_etaria.(df.IDADE_ANOS)      # a coluna IDADE_ANOS de process_sim/sih/sinan
source
MicroSUS.taxa_padronizada — Function
taxa_padronizada(casos, populacao, padrao; por = 100_000) -> NamedTuple

Taxa padronizada por idade pelo método direto: a taxa que a população estudada teria se tivesse a estrutura etária de padrao. Os três vetores são por faixa, na mesma ordem: casos (eventos), populacao (a do denominador) e padrao (a população-padrão, ou só os seus pesos).

Devolve taxa (padronizada), bruta (casos/população), erro_padrao (aproximação de Poisson: por² · Σ wᵢ² · casosᵢ / populaçãoᵢ²) e pesos.

pop = DataFrame(populacao_por_idade(2022; nivel = :uf))
br  = DataFrame(populacao_por_idade(2022; nivel = :brasil))   # padrão: Brasil, Censo 2022
# casos por faixa (com faixa_etaria nos microdados), alinhados às faixas de `pop`…
taxa_padronizada(casos, pe.populacao, br.populacao)

Para eventos raros, com poucos casos por faixa, o erro-padrão de Poisson subestima a incerteza; intervalos exatos (gama, Fay & Feuer 1997) pedem outra ferramenta.

source

Estruturas DBF

MicroSUS.CabecalhoDBF — Type
CabecalhoDBF

Cabeçalho de um DBF/DBC: contagem de registros, tamanhos do cabeçalho e do registro, language driver (ldid, decide o encoding) e os CampoDBF na ordem do arquivo (+ um índice por nome). Obtenha com MicroSUS.cabecalho sem ler nenhum dado.

source
MicroSUS.CampoDBF — Type
CampoDBF

Descritor de um campo DBF: nome, tipo ('C' texto, 'N' numérico, 'D' data aaaammdd, 'F', 'L'), largura, decimais e offset (0-based dentro do registro; o byte 0 é a flag de deleção).

source
MicroSUS.cabecalho — Function
cabecalho(caminho) -> CabecalhoDBF

Lê apenas o cabeçalho de um .dbc ou .dbf (campos, larguras, contagem de registros), sem descomprimir nem tocar nos dados.

É o primeiro comando de qualquer análise multi-ano: o layout do DATASUS muda entre anos, e conferir treze cabeçalhos custa menos que uma leitura.

cab = cabecalho("RDPE2201.dbc")
cab.n_registros                              # 48562
[c.nome for c in cab.campos]                 # nomes disponíveis
:DIAGSEC1 in keys(cab.indice)                # o campo existe neste ano?

Para ler apenas as colunas que existem em cada arquivo de uma série, combine com ler(...; ignorar_ausentes = true).

source

Baixo nível

MicroSUS.dcl_descomprime — Function
dcl_descomprime(io::IO, sink) -> Int

Descomprime um fluxo PKWare DCL ("implode") lido de io, chamando sink(chunk::AbstractVector{UInt8}) com blocos de até 4096 bytes à medida que a janela enche. Retorna o total de bytes descomprimidos. Memória constante (janela de 4 KiB). Porte do blast.c.

source
dcl_descomprime(io::IO) -> Vector{UInt8}

Versão de conveniência que materializa tudo num vetor (para arquivos pequenos ou testes). Prefira a versão com sink em produção.

source