Supplementary Health Data with ANS
Source:vignettes/ans-supplementary-health.Rmd
ans-supplementary-health.RmdOverview
The ANS (Agencia Nacional de Saude Suplementar) is Brazil’s regulatory agency for private/supplementary health insurance (planos de saude). Its open data portal provides data on beneficiaries, consumer complaints, and operator financial statements.
| Feature | Details |
|---|---|
| Source | HTTP CSV/ZIP (dadosabertos.ans.gov.br) |
| Data types | 3 (beneficiaries, complaints, financial) |
| Beneficiaries | Monthly, per-UF (Apr 2019–present) |
| Complaints | Annual, national (2011–present) |
| Financial | Quarterly (2007–present) |
| Operators | Snapshot registry (separate function) |
Data types
| Code | Name | Granularity | Availability |
|---|---|---|---|
| beneficiaries | Beneficiarios | Monthly, per-UF | Apr 2019–2025 |
| complaints | Demandas NIP | Annual, national | 2011–2026 |
| financial | Demonstracoes contabeis | Quarterly | 2007–2025 |
Beneficiaries
Beneficiary data provides consolidated counts of health plan enrollees broken down by operator, municipality, sex, age group, plan type, and more. Each file covers one state (UF) and one month.
Basic download
# Acre, December 2023
ac <- ans_data(year = 2023, month = 12, uf = "AC")
acKey variables
| Variable | Description |
|---|---|
| ID_CMPT_MOVEL | Reference period (YYYY-MM) |
| CD_OPERADORA | Operator code at ANS |
| NM_RAZAO_SOCIAL | Operator name |
| SG_UF | State abbreviation |
| CD_MUNICIPIO | Municipality (IBGE code) |
| TP_SEXO | Sex (M/F) |
| DE_FAIXA_ETARIA | Age group |
| DE_CONTRATACAO_PLANO | Contract type (Individual, Coletivo Empresarial, etc.) |
| DE_SEGMENTACAO_PLANO | Plan segment (Ambulatorial, Hospitalar, etc.) |
| COBERTURA_ASSIST_PLAN | Coverage type (Medico-hospitalar, Odontologica) |
| TIPO_VINCULO | Beneficiary link (Titular, Dependente) |
| QT_BENEFICIARIO_ATIVO | Active beneficiary count |
Consumer complaints (NIP)
Consumer complaints data covers demands filed through ANS’s NIP (Notificacao de Intermediacao Preliminar) system. Files are national (not per-UF) and annual.
# complaints filed in 2022
nip <- ans_data(year = 2022, type = "complaints")
nip
# multiple years
nip_multi <- ans_data(year = 2020:2023, type = "complaints")Key variables
| Variable | Description |
|---|---|
| NUMERO_DA_DEMANDA | Complaint number |
| ABERTURA_DA_DEMANDA | Filing date |
| ASSUNTO | Subject |
| REGISTRO_OPERADORA | Operator registration |
| NOME_OPERADORA | Operator name |
| TIPO_DE_PLANO_CONTRATADO | Contract type |
| SEXO | Sex (M/F) |
| ESTADO_DO_BENEFICIARIO | Beneficiary state |
| CLASSIFICACAO_DA_NIP | NIP classification |
| NATUREZA_DA_NIP | NIP nature |
| SITUACAO_DA_NIP | NIP status |
Financial statements
Quarterly financial statements (demonstracoes contabeis) for all health plan operators.
Operator registry
The operator registry is a separate snapshot (not time-series), so it uses its own function:
# active operators
active <- ans_operators()
# cancelled operators
cancelled <- ans_operators(status = "cancelled")
# both combined
all_ops <- ans_operators(status = "all")Exploring variables
# beneficiaries variables (default)
ans_variables()
# complaints variables
ans_variables(type = "complaints")
# financial variables
ans_variables(type = "financial")
# search across variables
ans_variables(search = "operadora")
ans_variables(search = "beneficiario")Example: operator financial health
# Q4 2023 financial data
fin <- ans_data(year = 2023, type = "financial", quarter = 4)
# join with operator registry for names
ops <- ans_operators()
fin |>
filter(grepl("^41", CD_CONTA_CONTABIL)) |> # revenue accounts
group_by(REG_ANS) |>
summarize(
revenue = sum(as.numeric(VL_SALDO_FINAL), na.rm = TRUE),
.groups = "drop"
) |>
left_join(
ops |> select(REGISTRO_OPERADORA, Razao_Social),
by = c("REG_ANS" = "REGISTRO_OPERADORA")
) |>
arrange(desc(revenue)) |>
head(10)Example: combining ANS with SUS data
ANS beneficiary counts complement SUS data by showing private coverage:
# private coverage (ANS)
ben <- ans_data(year = 2023, month = 12,
vars = c("SG_UF", "QT_BENEFICIARIO_ATIVO"))
private_by_uf <- ben |>
group_by(SG_UF) |>
summarize(
private_beneficiaries = sum(as.integer(QT_BENEFICIARIO_ATIVO), na.rm = TRUE),
.groups = "drop"
)
# total population (Census 2022)
pop <- censo_populacao(year = 2022, territorial_level = "state")
# private coverage rate
# private_by_uf |>
# left_join(pop, by = ...) |>
# mutate(coverage_pct = (private_beneficiaries / population) * 100) |>
# arrange(desc(coverage_pct))Parameter routing
ans_data() routes parameters based on the
type:
| Parameter | beneficiaries | complaints | financial |
|---|---|---|---|
year |
required | required | required |
month |
optional (1–12) | ignored | ignored |
uf |
optional (27 UFs + XX) | ignored | ignored |
quarter |
ignored | ignored | optional (1–4) |
vars |
optional | optional | optional |
Unused parameters emit a warning but do not cause errors.
Lazy evaluation
With the arrow package installed, data is cached in
Parquet format and can be queried lazily:
Cache management
Downloaded data is cached locally for faster future access:
# check cache status
ans_cache_status()
# clear cache if needed
ans_clear_cache()Differences from DATASUS modules
| Feature | ANS | DATASUS modules |
|---|---|---|
| Data source | HTTP CSV/ZIP | FTP .dbc/.DBF files |
| Column names | MixedCase (from CSV) | UPPERCASE |
parse parameter |
Not available | Available |
dictionary() |
Not available | Available |
quarter parameter |
Financial data | Not used |
| Operator registry | ans_operators() |
Not applicable |
Additional resources
- ANS open data portal (
dadosabertos.ans.gov.br) - ANS official website (
www.gov.br/ans/pt-br) - ANS Tabnet (
www.ans.gov.br/anstabnet) - Census vignette for population denominators