43º Batalhão de Polícia Militar - PMMG


Introdução

Curso: Pós Graduação em Ciência de Dados e Big Data
Disciplina: Visualização de Dados

Para resolução do exercício carregamos os pacotes necessários, utilizando dados dos últimos 24 meses do Banco de Dados de Roubo de Minas Gerais. A partir dessas informações, e cumprindo os requisitos da atividade, geramos tabelas interativas, 4 gráficos variados e mapas temáticos focados nas duas principais naturezas criminais registradas no período.


1. Instalação e Carregamento das Bibliotecas

# O trecho verifica se as bibliotecas estão instaladas e caso não estejam faz a instalação apenas das que não formam encontrasas
if(!require(ggplot2)){install.packages("ggplot2")}
if(!require(dplyr)){install.packages("dplyr")}
if(!require(lubridate)){install.packages("lubridate")}
if(!require(sf)){install.packages("sf")}
if(!require(DT)){install.packages("DT")}

library(ggplot2)
library(dplyr)
library(lubridate)
library(sf)
library(DT)

2. Coleta e Tratamento dos Dados

Realização da importação, tratamento dos dados, renomeia as colunas e tilização os filtros dos últimos 24 meses da base.

# Realiza a leitura dos arquivos CSV
dados_roubo <- read.csv2("Banco_Alvos_de_Roubo_Atualizado_Abril_2026.csv")
dados_furto <- read.csv2("Banco_Furto_Consumado_Atualizado_Abril_2026.csv")

# Padronização e seleção das colunas dos crimes de Roubo
# Colunas originais Roubo: Registros;Natureza;Alvos;Município;Cód. IBGE;Mês;Ano Fato;RISP;RMBH
dados_roubo_padrao <- dados_roubo %>%
  select(Ocorrencias = 1, Natureza = 2, Municipio = 4, Mes = 6, Ano = 7) %>%
  mutate(Categoria = "ROUBO")

# Padronização e seleção das colunas dos crimes de Furto
# Colunas originais Furto: Registros;Natureza;Município;Cód. IBGE;Mês;Ano Fato;RISP;RMBH
dados_furto_padrao <- dados_furto %>%
  select(Ocorrencias = 1, Natureza = 2, Municipio = 3, Mes = 5, Ano = 6) %>%
  mutate(Categoria = "FURTO")

# Cria as duas bases de dados
dados_brutos <- bind_rows(dados_roubo_padrao, dados_furto_padrao)

# Cria a coluna de Data juntando Ano e Mês
dados_brutos$Data <- make_date(dados_brutos$Ano, dados_brutos$Mes, 1)

# Descobre qual foi a última data e voltando 23 meses para dar 24 no total
data_max <- max(dados_brutos$Data, na.rm = TRUE)
data_min <- data_max %m-% months(23)

# Filtra as linhas pelo período (24 meses)
dados_tratados <- dados_brutos %>%
  filter(Data >= data_min & Data <= data_max)

# Para evitar reescrever todos os gráficos que já usam "Natureza", 
# reescrevemos a coluna Natureza com a Categoria (ROUBO x FURTO)
dados_tratados$Natureza <- dados_tratados$Categoria

Tabela Interativa de Dados

Apresentamos uma amostra interativa dos dados já tratados (primeiros 500 registros):

# Visualizando os registros com DT::datatable
datatable(head(dados_tratados, 500), 
          options = list(pageLength = 5, scrollX = TRUE),
          caption = "Amostra dos Registros Filtrados (24 meses e 2 categorias de Roubo)")

3. Análise Gráfica (4 Gráficos)

Com os dados extraídos e tratados, criamos 4 gráficos interativos

3.1. Comparativo Geral (Gráfico de Barras)

# Aplicação de agrupamento e soma dos dados
grafico_dados <- dados_tratados %>%
  group_by(Natureza) %>%
  summarise(Total = sum(Ocorrencias))

grafico_barras <- ggplot(grafico_dados, aes(x = Natureza, y = Total, fill = Natureza)) +
  geom_bar(stat = "identity") +
  scale_fill_manual(values = c("#FF9999", "#66B2FF")) +
  labs(
    title = "Comparação das Maiores Naturezas Criminais",
    x = "Tipo de Crime",
    y = "Total de Ocorrências no Período"
  ) +
  theme_minimal() +
  theme(legend.position = "none", axis.text.x = element_text(angle = 45, hjust = 1))

grafico_barras

3.2. Proporção das Naturezas (Gráfico de Rosca/Pizza)

dados_prop <- grafico_dados %>%
  mutate(Perc = Total / sum(Total) * 100)

grafico_pizza <- ggplot(dados_prop, aes(x = "", y = Perc, fill = Natureza)) +
  geom_bar(stat = "identity", width = 1, color = "white") +
  coord_polar("y", start = 0) +
  scale_fill_manual(values = c("#FF9999", "#66B2FF")) +
  labs(title = "Proporção dos Tipos de Roubo no Período", fill = "Natureza") +
  theme_void() +
  geom_text(aes(label = paste0(round(Perc, 1), "%")), position = position_stack(vjust = 0.5), color = "black", size = 5)

grafico_pizza

3.3. Evolução Temporal (Gráfico de Linha)

dados_tempo <- dados_tratados %>%
  group_by(Data, Natureza) %>%
  summarise(Total = sum(Ocorrencias))

grafico_tempo <- ggplot(dados_tempo, aes(x = Data, y = Total, color = Natureza)) +
  geom_line(size = 1) +
  geom_point(size = 2) +
  scale_color_manual(values = c("#FF9999", "#66B2FF")) +
  labs(
    title = "Evolução Temporal dos Roubos",
    x = "Mês e Ano",
    y = "Quantidade de Ocorrências"
  ) +
  scale_x_date(date_labels = "%b %Y", date_breaks = "2 months") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

grafico_tempo

3.4. Municípios com maior número de Ocorrências (Top 10 Municípios)

dados_top10 <- dados_tratados %>%
  group_by(Municipio) %>%
  summarise(Total = sum(Ocorrencias)) %>%
  arrange(desc(Total)) %>%
  slice(1:10)

grafico_top10 <- ggplot(dados_top10, aes(x = reorder(Municipio, Total), y = Total, fill = Total)) +
  geom_bar(stat = "identity") +
  coord_flip() +
  scale_fill_gradient(low = "#ffcccc", high = "#990000") +
  labs(
    title = "Top 10 Municípios com Maior Número de Roubos",
    x = "Município",
    y = "Total de Ocorrências"
  ) +
  theme_minimal() +
  theme(legend.position = "none")

grafico_top10


4. Mapa Temático de Minas Gerais

Nesta seção construímos o mapa de risco criminal, cruzando os dados das ocorrências do período utilizando a visualização da malha municipal do IBGE.

options(timeout = 600)

# URL direta do servidor do IBGE para a malha de MG de 2020
url_ibge <- "https://geoftp.ibge.gov.br/organizacao_do_territorio/malhas_territoriais/malhas_municipais/municipio_2020/UFs/MG/MG_Municipios_2020.zip"

if (!file.exists("MG_Municipios_2020.zip")) {
  download.file(url_ibge, destfile = "MG_Municipios_2020.zip", mode = "wb")
}

if (!dir.exists("malha_mg")) {
  unzip("MG_Municipios_2020.zip", exdir = "malha_mg")
}

mg_sf <- st_read("malha_mg/MG_Municipios_2020.shp")
mg_sf <- mg_sf %>% rename(name_muni = NM_MUN)

# Agrupando roubos por município
dados_mapa <- dados_tratados %>%
  group_by(Municipio) %>%
  summarise(Total_Ocorrencias = sum(Ocorrencias)) %>%
  mutate(name_muni = toupper(Municipio))

# Mesclagem
mg_sf_plot <- mg_sf %>%
  mutate(name_muni = toupper(name_muni)) %>%
  left_join(dados_mapa, by = "name_muni")

# Tratando NAs
mg_sf_plot$Total_Ocorrencias[is.na(mg_sf_plot$Total_Ocorrencias)] <- 0

# Classificação das faixas de risco
mg_sf_plot$Categoria_Crime <- cut(mg_sf_plot$Total_Ocorrencias,
                                  breaks = c(-1, 0, 10, 50, 100, Inf),
                                  labels = c("Nenhum caso", "Baixo", "Médio", "Alto", "Muito Alto (Crítico)"))
mapa_mg <- ggplot(data = mg_sf_plot) +
  geom_sf(aes(fill = Categoria_Crime), color = "gray30", size = 0.1) +
  scale_fill_manual(values = c("#F0F0F0", "#FFCC99", "#FF9999", "#FF3333", "#990000")) +
  labs(
    title = "Mapa de Risco Criminal em Minas Gerais",
    subtitle = "Acumulado dos últimos 24 meses das principais naturezas de roubo",
    fill = "Nível de Risco"
  ) +
  theme_void() +
  theme(legend.position = "right")

mapa_mg