O excesso de velocidade é um dos principais fatores contribuintes para acidentes de trânsito fatais no Brasil. Em áreas urbanas como o Recife, a fiscalização e o monitoramento das velocidades nas vias públicas representam uma importante estratégia para aumentar a segurança viária e reduzir a mortalidade no trânsito.
Este projeto analisa os dados coletados por equipamentos de fiscalização (lombadas eletrônicas e fotossensores) nas vias do Recife durante o ano de 2020, buscando compreender padrões de velocidade, identificar pontos críticos e oferecer insights para políticas públicas de segurança viária.
Este projeto utiliza dados públicos disponibilizados pela Prefeitura do Recife através do Portal de Dados Abertos (http://dados.recife.pe.gov.br/). O conjunto específico analisado é “Velocidade das Vias - Quantitativo por Velocidade Média - 2020”, que registra:
Nossa análise seguirá estas etapas principais:
Esta análise fornece insights valiosos para:
# Manipulação de dados
library(tidyverse) # Conjunto de pacotes para manipulação de dados
library(readr) # Importação eficiente de dados
library(lubridate) # Manipulação de datas
library(janitor) # Limpeza de nomes de variáveis
# Visualização
library(ggplot2) # Criação de gráficos
library(plotly) # Gráficos interativos
library(leaflet) # Mapas interativos
library(viridis) # Paletas de cores acessíveis
library(scales) # Formatação de escalas em gráficos
# Apresentação
library(knitr) # Geração de relatórios dinâmicos
library(kableExtra) # Tabelas formatadas
library(DT) # Tabelas interativas
library(flexdashboard) # Layout de dashboard
Propósito dos pacotes principais:
# Importando arquivo de localização dos equipamentos
lombadas_fotossensores <- read_delim("lombadas-fotossensores.csv",
delim = ";",
locale = locale(decimal_mark = ","),
col_types = cols(
equipamento = col_character(),
tipo = col_character(),
logradouro = col_character(),
velocidade_via = col_character(),
latitude = col_double(),
longitude = col_double()
))
# Função para importar dados mensais de fotossensores
importar_fotossensores_mensais <- function(mes) {
arquivo <- sprintf("recife-fotossensores-20-%s.csv", mes)
dados <- read_delim(arquivo,
delim = ";",
locale = locale(decimal_mark = ","),
col_types = cols(
mes = col_integer(),
equipamento = col_character(),
faixa = col_integer(),
data = col_date(format = ""),
hora = col_integer(),
minutos_intervalo = col_character(),
.default = col_integer()
))
return(dados)
}
# Função para importar dados mensais de lombadas
importar_lombadas_mensais <- function(mes) {
arquivo <- sprintf("%slomb2020.csv", mes)
dados <- read_delim(arquivo,
delim = ";",
locale = locale(decimal_mark = ","),
col_types = cols(
ano = col_integer(),
mes = col_character(),
equipamento = col_character(),
faixa = col_integer(),
data = col_date(format = ""),
hora = col_integer(),
minutos_intervalo = col_character(),
.default = col_integer()
))
return(dados)
}
# Importando o mês de janeiro para demonstração
fotossensores_janeiro <- importar_fotossensores_mensais("janeiro")
lombadas_janeiro <- importar_lombadas_mensais("janeiro")
# Exibindo primeiras linhas dos dados
cat("Equipamentos de monitoramento:\n")
## Equipamentos de monitoramento:
head(lombadas_fotossensores, 3) %>% kable()
| equipamento | tipo | logradouro | velocidade_via | latitude | longitude |
|---|---|---|---|---|---|
| 5941 | Lombada | AV. MAL. MASCARENHAS DE MORAES, EM FRENTE AEROPORTO - SENT. PRAZERES | 60 km/h | NA | NA |
| 5942 | Lombada | AV. MAL. MASCARENHAS DE MORAES, EM FRENTE AEROPORTO - SENT. CENTRO | 60 km/h | NA | NA |
| 5943 | Lombada | AV. BOA VIAGEM - TERCEIRO JARDIM | 60 km/h | NA | NA |
cat("\nDados de fotossensores (Janeiro 2020):\n")
##
## Dados de fotossensores (Janeiro 2020):
head(fotossensores_janeiro, 3) %>% kable()
| mes | equipamento | faixa | data | hora | minutos_intervalo | qtd_0a10km | qtd_11a20km | qtd_21a30km | qtd_31a40km | qtd_41a50km | qtd_51a60km | qtd_61a70km | qtd_71a80km | qtd_81a90km | qtd_91a100km | qtd_acimade100km |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | FS002REC | 1 | 2020-01-01 | 0 | 0-15 | 1 | 2 | 8 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 1 | FS002REC | 1 | 2020-01-01 | 0 | 16-30 | 0 | 8 | 8 | 3 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 1 | FS002REC | 1 | 2020-01-01 | 0 | 31-45 | 0 | 12 | 21 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
cat("\nDados de lombadas (Janeiro 2020):\n")
##
## Dados de lombadas (Janeiro 2020):
head(lombadas_janeiro, 3) %>% kable()
| ano | mes | equipamento | faixa | data | hora | minutos_intervalo | qtd_0a10km | qtd_11a20km | qtd_21a30km | qtd_31a40km | qtd_41a50km | qtd_51a60km | qtd_61a70km | qtd_71a80km | qtd_81a90km | qtd_91a100km | qtd_acimade100km |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2020 | 01 | 1 | 1 | 2020-01-01 | 10 | 10:00-10:15 | 0 | 2 | 1 | 7 | 25 | 13 | 0 | 0 | 0 | 0 | 0 |
| 2020 | 01 | 1 | 1 | 2020-01-01 | 10 | 10:15-10:30 | 0 | 0 | 0 | 6 | 9 | 8 | 0 | 0 | 0 | 0 | 0 |
| 2020 | 01 | 1 | 1 | 2020-01-01 | 10 | 10:30-10:45 | 1 | 0 | 2 | 9 | 13 | 7 | 0 | 0 | 0 | 0 | 0 |
# Corrigindo formato da velocidade na via
lombadas_fotossensores <- lombadas_fotossensores %>%
mutate(
# Extrair apenas o número da velocidade (removendo "km/h")
velocidade_via = as.integer(str_extract(velocidade_via, "\\d+"))
)
# Unificando os dados de fotossensores e lombadas (janeiro como exemplo)
lombadas_janeiro <- lombadas_janeiro %>%
# Garantir que mes seja numérico para consistência
mutate(mes = as.integer(mes))
# Função para transformar dados em formato longo (melhor para análise)
transformar_para_longo <- function(df) {
df %>%
pivot_longer(
cols = starts_with("qtd_"),
names_to = "faixa_velocidade",
values_to = "quantidade_veiculos"
) %>%
# Extrair limites de velocidade da faixa
mutate(
faixa_velocidade = case_when(
faixa_velocidade == "qtd_0a10km" ~ "0-10",
faixa_velocidade == "qtd_11a20km" ~ "11-20",
faixa_velocidade == "qtd_21a30km" ~ "21-30",
faixa_velocidade == "qtd_31a40km" ~ "31-40",
faixa_velocidade == "qtd_41a50km" ~ "41-50",
faixa_velocidade == "qtd_51a60km" ~ "51-60",
faixa_velocidade == "qtd_61a70km" ~ "61-70",
faixa_velocidade == "qtd_71a80km" ~ "71-80",
faixa_velocidade == "qtd_81a90km" ~ "81-90",
faixa_velocidade == "qtd_91a100km" ~ "91-100",
faixa_velocidade == "qtd_acimade100km" ~ ">100",
TRUE ~ faixa_velocidade
),
# Criar coluna com velocidade média da faixa (para cálculos)
velocidade_media = case_when(
faixa_velocidade == "0-10" ~ 5,
faixa_velocidade == "11-20" ~ 15,
faixa_velocidade == "21-30" ~ 25,
faixa_velocidade == "31-40" ~ 35,
faixa_velocidade == "41-50" ~ 45,
faixa_velocidade == "51-60" ~ 55,
faixa_velocidade == "61-70" ~ 65,
faixa_velocidade == "71-80" ~ 75,
faixa_velocidade == "81-90" ~ 85,
faixa_velocidade == "91-100" ~ 95,
faixa_velocidade == ">100" ~ 110,
TRUE ~ NA_real_
)
)
}
# Transformando os dados para formato longo
fotossensores_janeiro_longo <- transformar_para_longo(fotossensores_janeiro)
lombadas_janeiro_longo <- transformar_para_longo(lombadas_janeiro)
# Corrigindo a função adicionar_periodo
adicionar_periodo <- function(df) {
df %>%
mutate(
periodo = case_when(
hora >= 0 & hora < 6 ~ "Madrugada",
hora >= 6 & hora < 12 ~ "Manhã",
hora >= 12 & hora < 18 ~ "Tarde",
hora >= 18 & hora <= 23 ~ "Noite",
TRUE ~ "Desconhecido"
),
# Extrair dia da semana usando abordagem mais segura
dia_semana = factor(
wday(data),
levels = 1:7,
labels = c("Domingo", "Segunda", "Terça", "Quarta", "Quinta", "Sexta", "Sábado")
)
)
}
fotossensores_janeiro_longo <- adicionar_periodo(fotossensores_janeiro_longo)
lombadas_janeiro_longo <- adicionar_periodo(lombadas_janeiro_longo)
# Exibindo amostra dos dados transformados
cat("Dados de fotossensores em formato longo:\n")
## Dados de fotossensores em formato longo:
fotossensores_janeiro_longo %>%
head(5) %>%
select(data, hora, periodo, dia_semana, equipamento, faixa_velocidade, quantidade_veiculos) %>%
kable()
| data | hora | periodo | dia_semana | equipamento | faixa_velocidade | quantidade_veiculos |
|---|---|---|---|---|---|---|
| 2020-01-01 | 0 | Madrugada | Quarta | FS002REC | 0-10 | 1 |
| 2020-01-01 | 0 | Madrugada | Quarta | FS002REC | 11-20 | 2 |
| 2020-01-01 | 0 | Madrugada | Quarta | FS002REC | 21-30 | 8 |
| 2020-01-01 | 0 | Madrugada | Quarta | FS002REC | 31-40 | 2 |
| 2020-01-01 | 0 | Madrugada | Quarta | FS002REC | 41-50 | 0 |
# Corrigindo os identificadores de equipamentos nos dados de fotossensores
fotossensores_janeiro_longo <- fotossensores_janeiro_longo %>%
mutate(
# Remove o sufixo "REC" dos identificadores de equipamentos
equipamento = str_replace(equipamento, "REC$", "")
)
# Juntando dados de velocidade com localização dos equipamentos
fotossensores_janeiro_geo <- fotossensores_janeiro_longo %>%
left_join(
lombadas_fotossensores %>% select(equipamento, tipo, logradouro, velocidade_via, latitude, longitude),
by = "equipamento"
)
# Verificando quantidade de dados por tipo de equipamento
contagem_por_tipo <- fotossensores_janeiro_geo %>%
filter(!is.na(tipo)) %>%
group_by(tipo) %>%
summarise(
registros = n(),
equipamentos_distintos = n_distinct(equipamento)
)
# Calcular velocidade excedente
fotossensores_janeiro_geo <- fotossensores_janeiro_geo %>%
mutate(
# Determinar se está acima da velocidade permitida
acima_limite = ifelse(!is.na(velocidade_via) & velocidade_media > velocidade_via, TRUE, FALSE),
# Calcular o quanto excede (em km/h e percentual)
excesso_kmh = ifelse(acima_limite, velocidade_media - velocidade_via, 0),
excesso_percentual = ifelse(!is.na(velocidade_via), (velocidade_media / velocidade_via - 1) * 100, NA)
)
# Resumo dos dados por tipo de equipamento
kable(contagem_por_tipo, caption = "Quantidade de registros por tipo de equipamento")
| tipo | registros | equipamentos_distintos |
|---|---|---|
| Fotossensor | 2482095 | 30 |
# Exibir dados com informações de localização
fotossensores_janeiro_geo %>%
filter(!is.na(tipo)) %>%
select(data, equipamento, tipo, logradouro, velocidade_via, faixa_velocidade,
velocidade_media, quantidade_veiculos, acima_limite) %>%
head(5) %>%
kable()
| data | equipamento | tipo | logradouro | velocidade_via | faixa_velocidade | velocidade_media | quantidade_veiculos | acima_limite |
|---|---|---|---|---|---|---|---|---|
| 2020-01-01 | FS002 | Fotossensor | RUA MADRE DE DEUS, SEMAFORO 020. | 30 | 0-10 | 5 | 1 | FALSE |
| 2020-01-01 | FS002 | Fotossensor | RUA MADRE DE DEUS, SEMAFORO 020. | 30 | 11-20 | 15 | 2 | FALSE |
| 2020-01-01 | FS002 | Fotossensor | RUA MADRE DE DEUS, SEMAFORO 020. | 30 | 21-30 | 25 | 8 | FALSE |
| 2020-01-01 | FS002 | Fotossensor | RUA MADRE DE DEUS, SEMAFORO 020. | 30 | 31-40 | 35 | 2 | TRUE |
| 2020-01-01 | FS002 | Fotossensor | RUA MADRE DE DEUS, SEMAFORO 020. | 30 | 41-50 | 45 | 0 | TRUE |
# Exibir dados com informações de localização (sem filtrar por tipo)
fotossensores_janeiro_geo %>%
select(data, equipamento, tipo, logradouro, velocidade_via, faixa_velocidade,
velocidade_media, quantidade_veiculos, acima_limite) %>%
head(5) %>%
kable()
| data | equipamento | tipo | logradouro | velocidade_via | faixa_velocidade | velocidade_media | quantidade_veiculos | acima_limite |
|---|---|---|---|---|---|---|---|---|
| 2020-01-01 | FS002 | Fotossensor | RUA MADRE DE DEUS, SEMAFORO 020. | 30 | 0-10 | 5 | 1 | FALSE |
| 2020-01-01 | FS002 | Fotossensor | RUA MADRE DE DEUS, SEMAFORO 020. | 30 | 11-20 | 15 | 2 | FALSE |
| 2020-01-01 | FS002 | Fotossensor | RUA MADRE DE DEUS, SEMAFORO 020. | 30 | 21-30 | 25 | 8 | FALSE |
| 2020-01-01 | FS002 | Fotossensor | RUA MADRE DE DEUS, SEMAFORO 020. | 30 | 31-40 | 35 | 2 | TRUE |
| 2020-01-01 | FS002 | Fotossensor | RUA MADRE DE DEUS, SEMAFORO 020. | 30 | 41-50 | 45 | 0 | TRUE |
# Calculando estatísticas gerais
total_registros <- nrow(fotossensores_janeiro_longo)
total_veiculos <- sum(fotossensores_janeiro_longo$quantidade_veiculos, na.rm = TRUE)
total_equipamentos <- n_distinct(fotossensores_janeiro_longo$equipamento)
dias_distintos <- n_distinct(fotossensores_janeiro_longo$data)
# Valores ausentes
ausentes <- fotossensores_janeiro_geo %>%
summarise(across(everything(), ~sum(is.na(.)))) %>%
pivot_longer(everything(), names_to = "variavel", values_to = "valores_ausentes") %>%
filter(valores_ausentes > 0)
# Distribuição por faixa de velocidade
dist_velocidade <- fotossensores_janeiro_longo %>%
group_by(faixa_velocidade) %>%
summarise(
total_veiculos = sum(quantidade_veiculos, na.rm = TRUE),
pct = total_veiculos / sum(fotossensores_janeiro_longo$quantidade_veiculos, na.rm = TRUE) * 100
) %>%
arrange(faixa_velocidade)
# Estatísticas gerais em valueboxes
valueBox(formatC(total_veiculos, format="d", big.mark=","),
"Veículos registrados (Jan/2020)",
icon = "fa-car",
color = "primary")
16,259,554
valueBox(total_equipamentos,
"Equipamentos monitorados",
icon = "fa-camera",
color = "info")
30
valueBox(dias_distintos,
"Dias com registros",
icon = "fa-calendar-check",
color = "success")
31
# Exibir distribuição de velocidades
dist_velocidade %>%
kable(col.names = c("Faixa de Velocidade (km/h)", "Total de Veículos", "Percentual (%)"),
caption = "Distribuição de veículos por faixa de velocidade") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"))
| Faixa de Velocidade (km/h) | Total de Veículos | Percentual (%) |
|---|---|---|
| 0-10 | 94323 | 0.5801082 |
| 11-20 | 2100363 | 12.9177159 |
| 21-30 | 3673784 | 22.5946173 |
| 31-40 | 4678025 | 28.7709306 |
| 41-50 | 4358145 | 26.8035950 |
| 51-60 | 1225826 | 7.5391121 |
| 61-70 | 121662 | 0.7482493 |
| 71-80 | 5274 | 0.0324363 |
| 81-90 | 1076 | 0.0066176 |
| 91-100 | 319 | 0.0019619 |
| >100 | 757 | 0.0046557 |
# Gráfico de distribuição
ggplot(dist_velocidade, aes(x = faixa_velocidade, y = total_veiculos)) +
geom_col(fill = "steelblue") +
labs(title = "Distribuição de Veículos por Faixa de Velocidade",
x = "Faixa de Velocidade (km/h)",
y = "Quantidade de Veículos") +
theme_minimal() +
scale_y_continuous(labels = scales::comma)