Geography and epidemiological analysis

Renato Prado Siqueira

2026-10-06

Overview

The package includes an offline IBGE territorial reference and dependency-free helpers for common epidemiological calculations. These tools can be used with data retrieved through datasus or with any data frame that uses compatible identifiers.

Territorial reference

Inspect the current hierarchy at region, state or municipality level:

datasus_territorios("regiao")
#>   codigo_regiao sigla_regiao       regiao ufs municipios
#> 1             1            N        Norte   7        450
#> 2             2           NE     Nordeste   9       1794
#> 3             3           SE      Sudeste   4       1668
#> 4             4            S          Sul   3       1191
#> 5             5           CO Centro-Oeste   4        468
head(datasus_territorios("uf"))
#>   codigo_uf uf unidade_federacao codigo_regiao sigla_regiao regiao municipios
#> 1        11 RO          Rondônia             1            N  Norte         52
#> 2        12 AC              Acre             1            N  Norte         22
#> 3        13 AM          Amazonas             1            N  Norte         62
#> 4        14 RR           Roraima             1            N  Norte         15
#> 5        15 PA              Pará             1            N  Norte        144
#> 6        16 AP             Amapá             1            N  Norte         16
head(datasus_territorios("municipio", uf = "MS"))
#>   codigo_municipio    municipio codigo_uf uf  unidade_federacao codigo_regiao
#> 1          5000203   Água Clara        50 MS Mato Grosso do Sul             5
#> 2          5000252  Alcinópolis        50 MS Mato Grosso do Sul             5
#> 3          5000609      Amambai        50 MS Mato Grosso do Sul             5
#> 4          5000708    Anastácio        50 MS Mato Grosso do Sul             5
#> 5          5000807 Anaurilândia        50 MS Mato Grosso do Sul             5
#> 6          5000856     Angélica        50 MS Mato Grosso do Sul             5
#>   sigla_regiao       regiao codigo_regiao_imediata        regiao_imediata
#> 1           CO Centro-Oeste                 500002            Três Lagoas
#> 2           CO Centro-Oeste                 500004                  Coxim
#> 3           CO Centro-Oeste                 500009                Amambai
#> 4           CO Centro-Oeste                 500012 Aquidauana - Anastácio
#> 5           CO Centro-Oeste                 500007         Nova Andradina
#> 6           CO Centro-Oeste                 500007         Nova Andradina
#>   codigo_regiao_intermediaria regiao_intermediaria codigo_microrregiao
#> 1                        5001         Campo Grande               50007
#> 2                        5001         Campo Grande               50003
#> 3                        5002             Dourados               50010
#> 4                        5003              Corumbá               50002
#> 5                        5002             Dourados               50008
#> 6                        5002             Dourados               50011
#>     microrregiao codigo_mesorregiao                        mesorregiao
#> 1    Três Lagoas               5003        Leste de Mato Grosso do Sul
#> 2   Alto Taquari               5002 Centro Norte de Mato Grosso do Sul
#> 3       Dourados               5004     Sudoeste de Mato Grosso do Sul
#> 4     Aquidauana               5001       Pantanais Sul Mato-grossense
#> 5 Nova Andradina               5003        Leste de Mato Grosso do Sul
#> 6       Iguatemi               5004     Sudoeste de Mato Grosso do Sul

DATASUS commonly uses six-digit municipality codes, while IBGE publishes a seven-digit identifier. Normalize either form explicitly:

normalizar_codigo_ibge(
  c("500270", "500370"),
  nivel = "municipio",
  formato = "ibge"
)
#> [1] "5002704" "5003702"

validar_codigo_ibge() reports whether identifiers belong to the current reference:

validar_codigo_ibge(c("5002704", "5003702", "9999999"))
#> [1]  TRUE  TRUE FALSE

Add geography to observations

Use adicionar_territorio() to attach municipality, state and region information without changing row order:

events <- data.frame(
  codigo = c("500270", "500370"),
  ano = c(2025L, 2025L),
  casos = c(18L, 7L)
)

events <- adicionar_territorio(events, codigo = "codigo")
events
#>   codigo  ano casos codigo_municipio    municipio codigo_uf uf
#> 1 500270 2025    18          5002704 Campo Grande        50 MS
#> 2 500370 2025     7          5003702     Dourados        50 MS
#>    unidade_federacao codigo_regiao sigla_regiao       regiao
#> 1 Mato Grosso do Sul             5           CO Centro-Oeste
#> 2 Mato Grosso do Sul             5           CO Centro-Oeste
#>   codigo_regiao_imediata regiao_imediata codigo_regiao_intermediaria
#> 1                 500001    Campo Grande                        5001
#> 2                 500005        Dourados                        5002
#>   regiao_intermediaria codigo_microrregiao microrregiao codigo_mesorregiao
#> 1         Campo Grande               50004 Campo Grande               5002
#> 2             Dourados               50010     Dourados               5004
#>                          mesorregiao
#> 1 Centro Norte de Mato Grosso do Sul
#> 2     Sudoeste de Mato Grosso do Sul

The bundled hierarchy describes current territorial units. Historical observations are not automatically redistributed after boundary changes.

Make missing combinations explicit

Absent municipality-period combinations can be created before calculating rates or plotting a panel:

panel <- completar_territorios(
  events,
  codigo = "codigo",
  periodo = "ano",
  uf = "MS",
  periodos = 2023:2025,
  preencher = list(casos = 0)
)

Choose the territorial universe and periods explicitly. An absent record is not always equivalent to a true zero.

Join population denominators

juntar_populacao() requires unique population keys, preserves observation order and reports unmatched rows by default:

cases <- data.frame(
  codigo_municipio = c("5002704", "5003702"),
  ano = c(2025L, 2025L),
  casos = c(18L, 7L)
)
population <- data.frame(
  codigo_municipio = c("5002704", "5003702"),
  ano = c(2025L, 2025L),
  habitantes = c(925000, 95000)
)

analysis <- juntar_populacao(
  cases,
  population,
  por = c(
    codigo_municipio = "codigo_municipio",
    ano = "ano"
  ),
  coluna_populacao = "habitantes",
  nome = "habitantes"
)
analysis
#>   codigo_municipio  ano casos habitantes
#> 1          5002704 2025    18     925000
#> 2          5003702 2025     7      95000

Rates, proportions and case fatality

Vector helpers are useful for direct calculations:

calcular_taxa(
  eventos = c(10, 25),
  populacao = c(10000, 20000)
)
#> [1] 100 125
#> attr(,"multiplicador")
#> [1] 1e+05

intervalo_taxa(
  eventos = 10,
  populacao = 10000,
  confianca = 0.95
)
#>   eventos populacao taxa limite_inferior limite_superior
#> 1      10     10000  100        47.95389        183.9036

The grouped indicator engine aggregates counts before calculating the estimate. This is preferable to averaging rates calculated for individual rows:

taxa_incidencia(
  analysis,
  casos = "casos",
  populacao = "habitantes",
  grupo = "ano",
  confianca = 0.95
)
#>    ano numerador denominador taxa_incidencia limite_inferior limite_superior
#> 1 2025        25     1020000         2.45098        1.586145        3.618131

outcomes <- data.frame(
  ano = c(2024L, 2024L, 2025L, 2025L),
  casos = c(50, 30, 45, 35),
  obitos = c(2, 1, 1, 2)
)
letalidade(
  outcomes,
  obitos = "obitos",
  casos = "casos",
  grupo = "ano",
  confianca = 0.95
)
#>    ano numerador denominador letalidade limite_inferior limite_superior
#> 1 2024         3          80       3.75       0.7801187         10.5702
#> 2 2025         3          80       3.75       0.7801187         10.5702

proporcao() and taxa_mortalidade() use the same grouped interface.

Epidemiological calendar and moving averages

semana_epidemiologica(
  as.Date(c("2025-01-01", "2025-12-31", "2026-01-01"))
)
#>         data ano_epidemiologico semana_epidemiologica     inicio        fim
#> 1 2025-01-01               2025                     1 2024-12-29 2025-01-04
#> 2 2025-12-31               2025                    53 2025-12-28 2026-01-03
#> 3 2026-01-01               2025                    53 2025-12-28 2026-01-03
#>     codigo
#> 1 2025-W01
#> 2 2025-W53
#> 3 2025-W53

head(calendario_epidemiologico(2026))
#>   ano_epidemiologico semana_epidemiologica     inicio        fim   codigo
#> 1               2026                     1 2026-01-04 2026-01-10 2026-W01
#> 2               2026                     2 2026-01-11 2026-01-17 2026-W02
#> 3               2026                     3 2026-01-18 2026-01-24 2026-W03
#> 4               2026                     4 2026-01-25 2026-01-31 2026-W04
#> 5               2026                     5 2026-02-01 2026-02-07 2026-W05
#> 6               2026                     6 2026-02-08 2026-02-14 2026-W06

media_movel(
  c(2, 5, 3, 8, 7, 6, 9),
  janela = 3,
  parcial = TRUE
)
#> [1] 2.000000 3.500000 3.333333 5.333333 6.000000 7.000000 7.333333
#> attr(,"janela")
#> [1] 3
#> attr(,"alinhamento")
#> [1] "direita"

Direct age standardization

The package supplies WHO 2000–2025, Segi and Scandinavian standard populations:

head(populacao_padrao("oms"))
#>        0-4        5-9      10-14      15-19      20-24      25-29 
#> 0.08856900 0.08686960 0.08596991 0.08467037 0.08217124 0.07927225

Pass age-specific counts and populations to padronizar_idade():

standardized <- padronizar_idade(
  eventos = deaths_by_age$obitos,
  populacao = deaths_by_age$habitantes,
  idade = deaths_by_age$faixa_etaria,
  populacao_padrao = populacao_padrao("oms"),
  grupo = deaths_by_age$ano,
  confianca = 0.95
)