1. Introdução

1.1 Declaração do Problema

A aviação é um dos meios de transporte mais seguros que existem, e essa segurança vem de um trabalho constante de investigação de ocorrências aeronáuticas. No Brasil, quem coordena esse trabalho é o CENIPA (Centro de Investigação e Prevenção de Acidentes Aeronáuticos), responsável por registrar e investigar os acidentes, incidentes graves e incidentes da aviação civil.

Este projeto tenta entender onde, quando e por que essas ocorrências acontecem. Quais fases do voo concentram mais acidentes? Quais estados registram mais casos? Que fatores humanos e operacionais aparecem com mais frequência? E qual é o grau de letalidade de cada tipo de ocorrência? São perguntas que interessam tanto a quem estuda ciência de dados e quer praticar com uma base real e bagunçada quanto a quem se preocupa com segurança de voo, já que entender o padrão dos acidentes é o primeiro passo para evitá-los.

1.2 Dados e Metodologia

A análise usa os dados públicos de Ocorrências Aeronáuticas da Aviação Civil Brasileira, publicados pelo CENIPA no portal dados.gov.br. O conjunto vem em quatro arquivos CSV separados, ligados entre si por códigos de ocorrência:

  • ocorrencia.csv: a tabela central, uma linha por ocorrência;
  • aeronave.csv: dados das aeronaves envolvidas;
  • ocorrencia_tipo.csv: o tipo (ou tipos) de cada ocorrência;
  • fator_contribuinte.csv: os fatores que contribuíram, quando houve investigação.

A metodologia seguiu estas etapas:

  1. Importar os quatro CSVs (que vêm em Latin-1 e separados por ;);
  2. Juntar as quatro tabelas num único data frame de análise;
  3. Limpar e padronizar (valores ausentes mascarados, datas, campos numéricos, capitalização de texto);
  4. Criar variáveis derivadas (ano, faixa de horário, indicador de fatalidade, nível de dano como fator ordenado);
  5. Fazer a análise exploratória com tabelas e gráficos, alguns deles interativos.

A ideia foi ir do geral para o específico. Primeiro um panorama, comparando as três classificações de ocorrência e medindo a letalidade de cada uma. Depois o porquê dos eventos mais graves, olhando os fatores contribuintes. Em seguida, o momento do voo em que eles se concentram, a evolução ao longo dos anos, o perfil das aeronaves mais envolvidas e, por fim, a distribuição pelo país. Cada pergunta é respondida com uma tabela ou um gráfico e fechada com um comentário, para o relatório contar uma história em vez de só mostrar números soltos.

1.3 Abordagem Técnica

O trabalho foi feito em R, usando o tidyverse (dplyr, tidyr, stringr, lubridate) para manipular e limpar os dados. O tidyverse encaixa bem aqui porque há bastante tratamento de texto, datas e junções, e o encadeamento com %>% deixa cada transformação explícita e fácil de comentar.

A maior dificuldade é que os dados não vêm prontos. São quatro tabelas que precisam ser mescladas, com valores ausentes registrados de formas diferentes (***, NULL, texto vazio) e algumas relações de um para muitos: uma ocorrência pode ter vários tipos e vários fatores contribuintes. Por isso a estratégia foi agregar antes de juntar. As tabelas de um para muitos são primeiro reduzidas a uma linha por ocorrência (guardando o tipo e o fator principais e criando contadores) e só depois unidas à tabela central com left_join. Assim as linhas não se multiplicam à toa. Os marcadores de ausência viram NA já na leitura, as datas são padronizadas com o lubridate e o texto em caixa alta é normalizado com o stringr, para a mesma categoria não aparecer escrita de duas formas.

Na parte visual, o relatório mistura gráficos estáticos (ggplot2), gráficos interativos (plotly), tabelas navegáveis (DT) e um mapa (leaflet), de modo que o leitor possa explorar os dados por conta própria em vez de só olhar imagens fixas.

1.4 Valor para os Clientes da Análise

Os resultados interessam a públicos diferentes. Órgãos reguladores como CENIPA e ANAC podem usar os padrões para priorizar campanhas de segurança nas fases de voo e nos fatores mais críticos. Empresas aéreas e escolas de aviação podem direcionar treinamento para os tipos de ocorrência mais comuns nas suas operações. E pesquisadores e jornalistas ganham uma base já organizada para acompanhar a evolução da segurança de voo no Brasil. No fim, a análise transforma quatro arquivos brutos do governo em informação útil sobre segurança aérea.

2. Pacotes Requeridos

Os pacotes abaixo são necessários para replicar a análise. Eles precisam estar instalados antes da execução (install.packages("nome_do_pacote")).

library(dplyr)       # Manipulação e transformação dos dados (filter, mutate, join...)
library(tidyr)       # Reformulação de dados (pivot, separate, etc.)
library(stringr)     # Limpeza e padronização de texto (maiúsculas, espaços)
library(lubridate)   # Conversão e manipulação de datas
library(ggplot2)     # Gráficos estáticos baseados na gramática dos gráficos
library(plotly)      # Gráficos interativos (hover, zoom)
library(DT)          # Tabelas interativas com busca, ordenação e paginação
library(leaflet)     # Mapa interativo a partir de latitude/longitude
library(scales)      # Formatação de eixos (milhares, porcentagem)
library(knitr)       # Geração de tabelas e do relatório
library(kableExtra)  # Formatação avançada de tabelas estáticas

3. Preparação dos Dados

3.1 Fonte dos Dados

Os dados foram obtidos no Portal Brasileiro de Dados Abertos, no conjunto Ocorrências Aeronáuticas da Aviação Civil Brasileira, mantido pelo CENIPA:

https://dados.gov.br/dados/conjuntos-dados/ocorrencias-aeronauticas-da-aviacao-civil-brasileira

Os quatro arquivos (ocorrencia.csv, aeronave.csv, ocorrencia_tipo.csv e fator_contribuinte.csv) precisam estar na mesma pasta deste arquivo .Rmd.

# Os arquivos vêm separados por ";" e em codificação Latin-1 (ISO-8859-1),
# por isso é preciso informar 'sep' e 'fileEncoding' na leitura. Ler como UTF-8
# quebraria os acentos (ex.: o nível de dano "DESTRUÍDA").
ler_cenipa <- function(arquivo) {
  read.csv(
    arquivo,
    sep = ";",
    fileEncoding = "latin1",
    stringsAsFactors = FALSE,
    na.strings = c("", "NULL", "***")
  )
}

ocorrencia  <- ler_cenipa("ocorrencia.csv")
aeronave    <- ler_cenipa("aeronave.csv")
oc_tipo     <- ler_cenipa("ocorrencia_tipo.csv")
fator       <- ler_cenipa("fator_contribuinte.csv")

# Dimensões de cada tabela original
dim_orig <- tibble::tibble(
  Tabela   = c("ocorrencia", "aeronave", "ocorrencia_tipo", "fator_contribuinte"),
  Linhas   = c(nrow(ocorrencia), nrow(aeronave), nrow(oc_tipo), nrow(fator)),
  Colunas  = c(ncol(ocorrencia), ncol(aeronave), ncol(oc_tipo), ncol(fator))
)
dim_orig
## # A tibble: 4 × 3
##   Tabela             Linhas Colunas
##   <chr>               <int>   <int>
## 1 ocorrencia          14626      22
## 2 aeronave            14822      20
## 3 ocorrencia_tipo     15432       3
## 4 fator_contribuinte   9106       5

3.2 Descrição da Fonte Original

A base é mantida pelo CENIPA e reúne as ocorrências da aviação civil brasileira investigadas pelo órgão, com registros que vão de 2007 até 2026 (data da coleta). A finalidade original dos dados é dar transparência e apoiar a prevenção de acidentes: cada ocorrência registrada alimenta as estatísticas oficiais de segurança de voo.

Alguns pontos importantes da fonte:

  • São quatro tabelas relacionais, não um arquivo único. A tabela ocorrencia repete o mesmo código em cinco colunas (codigo_ocorrencia, codigo_ocorrencia1 a codigo_ocorrencia4), e cada uma serve de chave para uma das outras tabelas.
  • Os valores ausentes vêm mascarados como ***, NULL ou texto vazio, e por isso já são convertidos em NA na leitura.
  • Há relações de um para muitos. Uma mesma ocorrência pode ter vários tipos (ocorrencia_tipo tem mais linhas que ocorrencia) e vários fatores contribuintes. Além disso, só parte das ocorrências (em geral os acidentes) tem fatores investigados, então essa tabela cobre menos casos.
  • O texto vem em caixa alta e há uma mistura de tipos: datas em dd/mm/aaaa, números, texto e coordenadas geográficas com ponto decimal.

3.3 Limpeza e Preparação dos Dados

A preparação tem duas grandes etapas: (a) juntar as quatro tabelas e (b) limpar e enriquecer o resultado.

Etapa (a), junção. A tabela ocorrencia é a espinha dorsal. A aeronave junta-se quase um para um (a granularidade do conjunto final passa a ser uma linha por aeronave envolvida). Já ocorrencia_tipo e fator_contribuinte têm relação de um para muitos; se fossem unidas direto, as linhas se multiplicariam. Então essas duas são agregadas para uma linha por ocorrência antes do join, guardando o tipo e o fator principais e criando contadores (qtd_tipos, qtd_fatores).

# Remove as colunas de código redundantes, mantendo só 'codigo_ocorrencia'
ocorrencia <- ocorrencia %>%
  select(-codigo_ocorrencia1, -codigo_ocorrencia2,
         -codigo_ocorrencia3, -codigo_ocorrencia4)

# Agrega tipos: tipo principal + total de tipos por ocorrência
tipo_agg <- oc_tipo %>%
  group_by(codigo_ocorrencia1) %>%
  summarise(
    ocorrencia_tipo     = first(ocorrencia_tipo),
    taxonomia_tipo_icao = first(taxonomia_tipo_icao),
    qtd_tipos           = n(),
    .groups = "drop"
  )

# Agrega fatores: fator principal (nome/aspecto/área) + total de fatores
fator_agg <- fator %>%
  group_by(codigo_ocorrencia3) %>%
  summarise(
    fator_nome    = first(fator_nome),
    fator_area    = first(fator_area),
    fator_aspecto = first(fator_aspecto),
    qtd_fatores   = n(),
    .groups = "drop"
  )

# Junção encadeada (left joins a partir da ocorrência)
dados <- ocorrencia %>%
  left_join(aeronave, by = c("codigo_ocorrencia" = "codigo_ocorrencia2")) %>%
  left_join(tipo_agg,  by = c("codigo_ocorrencia" = "codigo_ocorrencia1")) %>%
  left_join(fator_agg, by = c("codigo_ocorrencia" = "codigo_ocorrencia3"))

dim(dados)  # linhas x colunas do conjunto unido
## [1] 14822    44

Etapa (b), limpeza e enriquecimento. Aqui os tipos são padronizados e são criadas as variáveis derivadas que aparecem na análise. Cada passo abaixo tem um comentário explicando o porquê.

dados_limpos <- dados %>%
  mutate(
    # Datas: o original vem como texto "dd/mm/aaaa" -> converter para Date real
    ocorrencia_dia = dmy(ocorrencia_dia),
    # Variável derivada: ano (útil para análise temporal)
    ano = year(ocorrencia_dia),

    # Converter campos numéricos que vieram como texto
    fatalidades    = as.integer(aeronave_fatalidades_total),
    assentos       = as.integer(aeronave_assentos),
    ano_fabricacao = as.integer(aeronave_ano_fabricacao),
    latitude       = as.numeric(ocorrencia_latitude),
    longitude      = as.numeric(ocorrencia_longitude),

    # Padronizar texto em Caixa de Título (evita "EMBRAER" vs "Embraer")
    fabricante = str_to_title(str_squish(aeronave_fabricante)),
    cidade     = str_to_title(str_squish(ocorrencia_cidade)),

    # Classificação como fator ordenado por gravidade
    classificacao = factor(
      ocorrencia_classificacao,
      levels = c("INCIDENTE", "INCIDENTE GRAVE", "ACIDENTE")
    ),

    # Nível de dano como fator ordenado
    nivel_dano = factor(
      aeronave_nivel_dano,
      levels = c("NENHUM", "LEVE", "SUBSTANCIAL", "DESTRUÍDA")
    ),

    # Variável derivada: a ocorrência teve ao menos uma fatalidade?
    teve_fatalidade = ifelse(!is.na(fatalidades) & fatalidades > 0,
                             "Com fatalidade", "Sem fatalidade"),

    # Faixa de horário (a partir da hora "hh:mm:ss")
    hora_num = as.integer(substr(ocorrencia_hora, 1, 2)),
    periodo  = case_when(
      hora_num >= 5  & hora_num < 12 ~ "Manhã",
      hora_num >= 12 & hora_num < 18 ~ "Tarde",
      hora_num >= 18 & hora_num < 24 ~ "Noite",
      TRUE                           ~ "Madrugada"
    )
  ) %>%
  # Mantém apenas registros com data válida e ano dentro do esperado
  filter(!is.na(ano), ano >= 2007, ano <= 2026)

dim(dados_limpos)
## [1] 14822    57

3.4 Dataset Final

Abaixo, uma amostra do conjunto final já limpo (algumas colunas de interesse e as primeiras linhas), em tabela interativa para não imprimir um data frame gigante.

dados_limpos %>%
  select(ano, classificacao, ocorrencia_uf, cidade, fabricante,
         aeronave_fase_operacao, ocorrencia_tipo, nivel_dano, fatalidades) %>%
  head(50) %>%
  DT::datatable(
    rownames = FALSE,
    options = list(pageLength = 10, scrollX = TRUE),
    colnames = c("Ano", "Classificação", "UF", "Cidade", "Fabricante",
                 "Fase do Voo", "Tipo de Ocorrência", "Nível de Dano", "Fatalidades"),
    caption = "Amostra (50 primeiras linhas) do conjunto final limpo"
  )

3.5 Resumo das Variáveis de Interesse

A tabela a seguir resume, de forma direta, as principais variáveis usadas na análise exploratória.

Tabela 1: Variáveis de interesse do conjunto final
Variável Tipo Descrição
ano Numérica Ano da ocorrência (2007 a 2026), derivado da data.
classificacao Fator Incidente, Incidente Grave ou Acidente (ordem de gravidade).
ocorrencia_uf Texto Unidade da Federação onde ocorreu.
fabricante Texto Fabricante da aeronave, padronizado.
aeronave_fase_operacao Texto Fase do voo (decolagem, cruzeiro, pouso, etc.).
ocorrencia_tipo Texto Tipo principal da ocorrência (ex.: colisão com ave).
fator_nome Texto Fator contribuinte principal (quando investigado).
fator_area Fator Área do fator (humano, operacional, material).
nivel_dano Fator Dano à aeronave (de nenhum a destruída).
fatalidades Numérica Total de fatalidades na aeronave.
teve_fatalidade Fator Indicador derivado: houve ao menos uma morte?
periodo Fator Faixa do dia (manhã/tarde/noite/madrugada).

4. Análise Exploratória dos Dados

Daqui em diante o relatório segue o roteiro anunciado na introdução, do panorama geral até o detalhe geográfico, com uma pergunta guiando cada subseção.

4.1 Panorama Geral: Classificação e Letalidade

A primeira pergunta natural é: das três classificações, qual é de fato perigosa? A tabela abaixo cruza a quantidade de registros com o número de mortes e a taxa de fatalidade (proporção de registros com ao menos uma morte).

tab_class <- dados_limpos %>%
  group_by(classificacao) %>%
  summarise(
    registros = n(),
    com_morte = sum(teve_fatalidade == "Com fatalidade", na.rm = TRUE),
    mortes    = sum(fatalidades, na.rm = TRUE),
    .groups = "drop"
  ) %>%
  mutate(taxa_fatalidade = round(com_morte / registros * 100, 1)) %>%
  arrange(classificacao)

tab_class %>%
  kable(
    caption = "Tabela 2: Registros, mortes e taxa de fatalidade por classificação",
    col.names = c("Classificação", "Registros", "Com fatalidade",
                  "Total de mortes", "Taxa de fatalidade (%)"),
    format.args = list(big.mark = ".")
  ) %>%
  kable_styling(bootstrap_options = c("striped", "hover")) %>%
  row_spec(which(tab_class$classificacao == "ACIDENTE"),
           bold = TRUE, color = "white", background = "#d73027")
Tabela 2: Registros, mortes e taxa de fatalidade por classificação
Classificação Registros Com fatalidade Total de mortes Taxa de fatalidade (%)
INCIDENTE 10.500 0 0 0.0
INCIDENTE GRAVE 1.304 0 0 0.0
ACIDENTE 3.018 707 1.704 23.4

Insight: os incidentes são a maioria absoluta dos registros, mas têm taxa de fatalidade praticamente nula, ou seja, são eventos sem dano grave. Quase toda a mortalidade está na categoria acidente, onde cerca de 23% dos registros envolvem ao menos uma fatalidade. A gravidade, portanto, não está no volume de ocorrências, e sim na classificação: poucos acidentes respondem por todas as mortes da base.

4.2 Fatores Contribuintes: por que os acidentes acontecem?

Quando o CENIPA investiga um acidente, ele registra os fatores contribuintes, agrupados em áreas (humano, operacional, material). O gráfico interativo abaixo mostra os fatores mais frequentes.

top_fatores <- dados_limpos %>%
  filter(!is.na(fator_nome)) %>%
  count(fator_nome, fator_area, sort = TRUE) %>%
  slice_head(n = 10) %>%
  arrange(n) %>%   # do menor para o maior, para a barra maior ficar no topo
  mutate(fator_nome = factor(fator_nome, levels = fator_nome))

# Construído direto no plot_ly: o ggplotly funde barras de cor única num retângulo só
plot_ly(
  top_fatores,
  x = ~n, y = ~fator_nome,
  color = ~fator_area, colors = "Set2",
  type = "bar", orientation = "h",
  hovertext = ~paste0(fator_nome, "<br>", n, " registros"),
  hoverinfo = "text"
) %>%
  layout(
    barmode = "stack",
    title = "Top 10 fatores contribuintes",
    xaxis = list(title = "Número de registros"),
    yaxis = list(title = ""),
    legend = list(title = list(text = "Área do fator"))
  )

Insight: os fatores que mais aparecem são de natureza humana e operacional (julgamento de pilotagem, aplicação de comandos, planejamento de voo), e não falhas mecânicas. Isso bate com uma ideia já conhecida na segurança de voo: a maior parte dos acidentes está ligada a decisão e desempenho humano, não a defeito de máquina. É um achado útil porque mostra que treinamento e procedimentos têm bastante potencial de prevenção.

4.3 Em que fase do voo os acidentes se concentram?

A próxima pergunta olha só para os acidentes e em que fase do voo eles acontecem.

fases <- dados_limpos %>%
  filter(classificacao == "ACIDENTE", !is.na(aeronave_fase_operacao)) %>%
  count(aeronave_fase_operacao, sort = TRUE) %>%
  slice_head(n = 8) %>%
  mutate(fase = reorder(str_to_title(aeronave_fase_operacao), n))

ggplot(fases, aes(x = n, y = fase)) +
  geom_col(fill = "#2c7fb8") +
  geom_text(aes(label = n), hjust = -0.15, size = 3.5) +
  scale_x_continuous(expand = expansion(mult = c(0, 0.12))) +
  labs(
    title = "Acidentes por fase do voo (Top 8)",
    subtitle = "Decolagem e pouso concentram os momentos mais críticos",
    x = "Número de acidentes", y = NULL
  ) +
  theme_minimal(base_size = 12)

Insight: os acidentes se concentram nas fases de decolagem e pouso, quando a aeronave está perto do solo, em baixa velocidade e com a tripulação numa carga de trabalho maior. As fases de cruzeiro, mesmo durando bem mais tempo, aparecem com menos acidentes. É a confirmação da velha máxima da aviação de que decolagem e pouso são as etapas mais delicadas do voo.

4.4 Evolução ao longo do tempo

Entendido o quê e o porquê, a pergunta seguinte é quando: como o número de ocorrências e de mortes se comportou ao longo dos anos? O primeiro gráfico mostra a quantidade de ocorrências por ano, separada por classificação.

por_ano <- dados_limpos %>%
  filter(!is.na(classificacao)) %>%
  count(ano, classificacao)

g_ano <- ggplot(por_ano,
                aes(x = ano, y = n, color = classificacao,
                    text = paste0(classificacao, "<br>", ano, ": ", n, " registros"))) +
  geom_line(aes(group = classificacao), linewidth = 0.9) +
  geom_point(size = 1.6) +
  scale_color_manual(values = c("INCIDENTE" = "#2c7fb8",
                                "INCIDENTE GRAVE" = "#fdae61",
                                "ACIDENTE" = "#d73027"),
                     name = "Classificação") +
  labs(title = "Ocorrências por ano e classificação",
       x = "Ano", y = "Número de ocorrências") +
  theme_minimal(base_size = 12)

ggplotly(g_ano, tooltip = "text")

Em seguida, só o total de mortes por ano. Como visto em 4.1, a mortalidade vem inteira dos acidentes.

mortes_ano <- dados_limpos %>%
  group_by(ano) %>%
  summarise(mortes = sum(fatalidades, na.rm = TRUE), .groups = "drop")

ggplot(mortes_ano, aes(x = ano, y = mortes)) +
  geom_col(fill = "#922922") +
  geom_text(aes(label = mortes), vjust = -0.4, size = 3) +
  scale_x_continuous(breaks = seq(2007, 2026, 2)) +
  labs(title = "Total de mortes por ano",
       x = "Ano", y = "Mortes") +
  theme_minimal(base_size = 12)

Insight: o volume de ocorrências registradas cresce ao longo do período, mas isso não quer dizer que voar ficou mais perigoso. Boa parte do aumento reflete mais registros e mais incidentes leves sendo reportados (cultura de notificação e regulação mais rígida), já que são os incidentes que puxam a curva para cima. As mortes, por outro lado, não mostram tendência clara de crescimento e oscilam de um ano para outro. Vale lembrar que 2026 aparece com números baixos por ser um ano incompleto (a coleta foi feita no meio do ano), então esse último ponto deve ser lido com cuidado.

4.5 Perfil das aeronaves envolvidas

Outra pergunta de interesse é quais aeronaves mais aparecem nas ocorrências. O gráfico abaixo traz os dez fabricantes mais frequentes.

top_fab <- dados_limpos %>%
  filter(!is.na(fabricante), fabricante != "") %>%
  count(fabricante, sort = TRUE) %>%
  slice_head(n = 10) %>%
  arrange(n) %>%   # menor -> maior, para a barra maior ficar no topo
  mutate(fabricante = factor(fabricante, levels = fabricante))

plot_ly(
  top_fab,
  x = ~n, y = ~fabricante,
  type = "bar", orientation = "h",
  marker = list(color = "#41ab5d"),
  hovertext = ~paste0(fabricante, "<br>", n, " ocorrências"),
  hoverinfo = "text"
) %>%
  layout(
    title = "Top 10 fabricantes por número de ocorrências",
    xaxis = list(title = "Número de ocorrências"),
    yaxis = list(title = "")
  )

Contar ocorrências por fabricante, sozinho, engana: quem tem mais aeronaves voando tende a aparecer mais. Por isso a tabela abaixo cruza, para os fabricantes com volume relevante (pelo menos 100 registros), o total de ocorrências com a proporção que foi acidente, uma forma melhor de comparar gravidade.

perfil_fab <- dados_limpos %>%
  filter(!is.na(fabricante), fabricante != "") %>%
  group_by(fabricante) %>%
  summarise(
    total     = n(),
    acidentes = sum(classificacao == "ACIDENTE", na.rm = TRUE),
    .groups = "drop"
  ) %>%
  filter(total >= 100) %>%
  mutate(pct_acidente = round(acidentes / total * 100, 1)) %>%
  arrange(desc(total)) %>%
  slice_head(n = 10)

perfil_fab %>%
  kable(
    caption = "Tabela 3: Fabricantes mais frequentes e proporção de acidentes",
    col.names = c("Fabricante", "Total de ocorrências", "Acidentes",
                  "% que foi acidente"),
    format.args = list(big.mark = ".")
  ) %>%
  kable_styling(bootstrap_options = c("striped", "hover"))
Tabela 3: Fabricantes mais frequentes e proporção de acidentes
Fabricante Total de ocorrências Acidentes % que foi acidente
Embraer 1.708 240 14.1
Cessna Aircraft 1.700 546 32.1
Boeing 1.426 3 0.2
Airbus 1.373 8 0.6
Piper Aircraft 738 231 31.3
Neiva 700 337 48.1
Atr - Gie Avions De Transport Régional 670 6 0.9
Boeing Company 634 4 0.6
Desconhecido 520 165 31.7
Beech Aircraft 508 137 27.0

Insight: os fabricantes que mais aparecem são, em boa parte, marcas ligadas à aviação geral e a aeronaves de pequeno porte (Cessna, Neiva, Piper, Embraer), e não as gigantes da aviação comercial. Faz sentido, já que há muito mais aeronaves pequenas voando. Mais revelador que o total bruto é a proporção de acidentes: enquanto os fabricantes ligados à aviação comercial concentram seus registros em incidentes não fatais, os de aviação geral têm uma fatia bem maior de acidentes de fato. O perfil de risco varia menos pela marca em si e mais pelo tipo de operação em que cada aeronave costuma ser usada.

4.6 Onde acontecem: distribuição geográfica

Por fim, a pergunta onde. Primeiro um ranking das Unidades da Federação com mais ocorrências, depois um mapa interativo com a localização dos acidentes que têm coordenadas registradas.

top_uf <- dados_limpos %>%
  filter(!is.na(ocorrencia_uf), ocorrencia_uf != "") %>%
  count(ocorrencia_uf, sort = TRUE) %>%
  slice_head(n = 12) %>%
  arrange(n) %>%   # menor -> maior, para a UF com mais casos ficar no topo
  mutate(ocorrencia_uf = factor(ocorrencia_uf, levels = ocorrencia_uf))

plot_ly(
  top_uf,
  x = ~n, y = ~ocorrencia_uf,
  type = "bar", orientation = "h",
  marker = list(color = "#756bb1"),
  hovertext = ~paste0("UF: ", ocorrencia_uf, "<br>", n, " ocorrências"),
  hoverinfo = "text"
) %>%
  layout(
    title = "Top 12 estados (UF) por número de ocorrências",
    xaxis = list(title = "Número de ocorrências"),
    yaxis = list(title = "")
  )
# Mantém só acidentes com coordenadas plausíveis dentro do território brasileiro
acidentes_geo <- dados_limpos %>%
  filter(classificacao == "ACIDENTE",
         !is.na(latitude), !is.na(longitude),
         between(latitude, -34, 6),
         between(longitude, -74, -33))

leaflet(acidentes_geo) %>%
  addProviderTiles(providers$CartoDB.Positron) %>%
  addCircleMarkers(
    lng = ~longitude, lat = ~latitude,
    radius = 4, stroke = FALSE, fillOpacity = 0.6,
    clusterOptions = markerClusterOptions(),
    popup = ~paste0("<b>", cidade, " (", ocorrencia_uf, ")</b><br>",
                    "Ano: ", ano, "<br>",
                    "Tipo: ", ocorrencia_tipo)
  )

Insight: as ocorrências se concentram bastante em São Paulo e na região Sudeste, seguida pelo Sul, acompanhando o volume de tráfego aéreo e a quantidade de aeroportos dessas regiões: onde se voa mais, registra-se mais. Ainda assim, o mapa mostra que os acidentes se espalham pelo país todo, inclusive pelo interior e pela região amazônica, onde a aviação de pequeno porte tem papel importante no transporte. Como nem todo registro tem coordenadas, o mapa exibe só os acidentes geolocalizados, mas mesmo assim o padrão de concentração no Sudeste se mantém.

5. Conclusões

5.1 Retomada do problema

O projeto partiu de uma pergunta ampla: onde, quando e por que acontecem as ocorrências da aviação civil brasileira, e qual o grau de letalidade de cada tipo. Para responder, foi preciso transformar quatro arquivos públicos e desorganizados do CENIPA num único conjunto de análise e percorrer, da visão geral ao detalhe, as classificações, os fatores, as fases de voo, a evolução temporal, o perfil das aeronaves e a distribuição geográfica.

5.2 Dados e metodologia utilizados

Os dados vieram do portal dados.gov.br, em quatro CSVs relacionais com codificação Latin-1, separador ; e valores ausentes mascarados. O trabalho seguiu o fluxo clássico de ciência de dados: importação, junção, limpeza e análise exploratória, tudo em R com o tidyverse. A decisão técnica mais importante foi agregar as tabelas de um para muitos antes de juntá-las, preservando o tipo e o fator principais de cada ocorrência sem multiplicar linhas. A partir daí, as variáveis derivadas (ano, faixa de horário, indicador de fatalidade, nível de dano ordenado) abriram caminho para as análises, apresentadas com tabelas e gráficos estáticos e interativos.

5.3 Principais descobertas

Os resultados se reforçam e contam uma história coerente:

  • A gravidade está na classificação, não no volume. Incidentes são a maioria, mas praticamente sem mortes; toda a mortalidade está nos acidentes, com cerca de 23% deles envolvendo ao menos uma fatalidade.
  • Os fatores humanos e operacionais (julgamento de pilotagem, aplicação de comandos, planejamento de voo) dominam as causas investigadas, bem acima das falhas de máquina.
  • Os acidentes se concentram nas fases de decolagem e pouso, os momentos mais críticos do voo.
  • Ao longo do tempo, o registro de ocorrências cresce (puxado por incidentes e por uma cultura de notificação mais forte), enquanto as mortes não mostram tendência clara de alta.
  • No perfil das aeronaves, marcas de aviação geral aparecem mais e com maior proporção de acidentes, enquanto a aviação comercial concentra incidentes não fatais. O risco acompanha mais o tipo de operação do que a marca.
  • Geograficamente, há forte concentração em São Paulo e no Sudeste, acompanhando o volume de tráfego, mas os acidentes se espalham pelo país todo.

5.4 Implicações para os públicos interessados

Para o CENIPA e a ANAC, os dados sugerem que campanhas e fiscalização rendem mais se focadas em decolagem e pouso, em fatores humanos e na aviação geral. Para empresas aéreas e escolas de aviação, o caminho passa por treinamento de tomada de decisão e procedimentos, não só por manutenção de equipamentos. E para pesquisadores e jornalistas, o conjunto, agora limpo e unificado, vira uma base pronta para acompanhar a evolução da segurança de voo no Brasil.

5.5 Limitações e próximos passos

A análise tem limites que convém deixar claros. Os fatores contribuintes só são investigados em parte das ocorrências (sobretudo acidentes), então não dá para estender essas causas aos incidentes. As contagens brutas refletem o tamanho da frota e a intensidade de notificação, não o risco puro; faltaria um denominador de exposição (como horas de voo ou número de decolagens) para comparações justas. O mapa mostra apenas os registros com coordenadas válidas, e o ano de 2026 está incompleto. Além disso, a agregação guardou só o tipo e o fator principais, deixando os secundários de fora.

Como próximos passos, seria interessante normalizar as ocorrências por movimentos ou horas de voo, construir um mapa coroplético por estado com dados oficiais de fronteiras, modelar a severidade em função das variáveis disponíveis e cruzar a base com dados de frota para medir risco relativo. Mesmo com esses limites, a análise cumpre o objetivo de transformar quatro arquivos brutos numa leitura clara dos padrões de segurança da aviação civil brasileira.