Introdução

A violência de gênero é uma realidade urgente e alarmante em Pernambuco. Ela ameaça não só a integridade física das vítimas, mas também seu bem-estar emocional, social e econômico. Cada registro no sistema de saúde representa mais que um número: ele revela histórias de agressões que exigem atenção e ações eficazes.

Utilizei os dados do SINAN – Sistema de Informação de Agravos de Notificação do Brasil, integrados com bases do Instituto Brasileiro de Geografia e Estatística (municípios-IBGE) e do Ministério da Saúde (CNES – Cadastro Nacional de Estabelecimentos de Saúde). A partir desses cruzamentos, é possível padronizar localidades e identificar as unidades notificadoras, trazendo maior precisão à análise.

Este estudo, desenvolvido no contexto de uma Iniciação Científica, explora os registros de violência notificados no estado entre 2023 e 2024. Devido a esse vínculo, algumas etapas de pré-processamento, como a conversão da idade codificada para a idade real e a tradução de variáveis categóricas, já foram estruturadas previamente, seguindo rigorosamente o Dicionário de Dados do SINAN.

A estratégia analítica adotada combina uma exploração descritiva — detalhando frequências por faixa etária, tipologia da violência, local de ocorrência e sexo — com a cartografia dos serviços de saúde que recebem essas notificações. O foco central é compreender os padrões, tendências e desigualdades presentes nos dados, fornecendo um diagnóstico robusto para gestores, pesquisadores e a sociedade civil.

Por fim, os insights gerados possuem o objetivo de apoiar a formulação de políticas de prevenção mais informadas, permitir um melhor direcionamento de recursos em saúde pública e fomentar debates sociais mais profundos sobre as dinâmicas da violência de gênero em Pernambuco.

Pacotes Necessários

A tabela abaixo lista as bibliotecas essenciais para a execução deste projeto, detalhando o propósito de cada uma:

Lista de bibliotecas utilizadas neste projeto
Nome.do.Pacote Propósito
tidyverse Manipulação, filtragem e visualização de dados (dplyr/ggplot2)
lubridate Tratamento e conversão de datas
readxl Importação de arquivos no formato Excel (.xlsx)
janitor Limpeza automática de nomes de colunas e dados
geobr Obtenção de dados geográficos do IBGE
sf Análise e manipulação de dados geoespaciais (cartografia)
DT Criação de tabelas HTML interativas
knitr Geração de relatórios e tabelas no RMarkdown
stringi Manipulação de texto e remoção de acentos (essencial para os mapas)
library(tidyverse)
library(lubridate)
library(readxl)
library(janitor)
library(geobr)
library(sf)
library(DT)
library(knitr)
library(stringi)

Preparação dos Dados

3.1 Introdução

Nesta etapa são carregados os bancos de dados (2023 e 2024), seguidos pelos processos de padronização, tratamento de datas, interpretação da idade real e integração das unidades notificadoras com a base do CNES.

Os dados utilizados neste trabalho são provenientes do Sistema de Informação de Agravos de Notificação (SINAN), disponibilizado pelo Ministério da Saúde via plataforma DATASUS (https://datasus.saude.gov.br/transferencia-de-arquivos/# ). O SINAN reúne notificações de agravos registradas por diferentes serviços de saúde em todo o país. Os arquivos originais correspondem aos anos de 2023 e 2024, fornecidos em formato DTB e contendo registros individuais de notificações de violência.

Como esses dados já haviam sido utilizados em minha Iniciação Científica, foi realizada previamente a conversão dos arquivos DTB para o formato .xlsx, preservando a estrutura original. É importante destacar que o propósito do SINAN é a vigilância epidemiológica, e não a produção de bases otimizadas para análises estatísticas — o que exige cuidados adicionais na etapa de limpeza.

Cada arquivo possui dezenas de variáveis relacionadas a:

Datas: notificação, ocorrência e outras.

Informações demográficas: idade, sexo e municípios de residência/notificação.

Características da violência: tipo, meio, relação com o agressor e local.

Campos administrativos: códigos e informações próprias do SINAN.

Os dados apresentam particularidades típicas de sistemas de vigilância, como valores ausentes (células vazias ou códigos como 99 – Ignorado), inconsistências temporais (ex.: notificação posterior à ocorrência), variações de categorias entre anos e nomes de colunas com acentos ou formatação diferente, exigindo padronização.

Diante disso, a etapa de preparação torna-se essencial. Nesta fase, realizou-se a importação dos arquivos, a união das bases de 2023 e 2024, a padronização dos nomes das variáveis, o tratamento das datas e a correção das inconsistências necessárias para garantir a qualidade analítica dos dados.

3.2 Importação e União das Bases

A primeira etapa consiste em carregar os arquivos referentes a 2023 e 2024. Utilizou-se a função read_excel() (pacote readxl) para a leitura dos arquivos .xlsx.

Durante a importação, definiu-se explicitamente o argumento col_types = “text”. Essa medida é crucial ao lidar com dados do SINAN para evitar erros de incompatibilidade de tipos entre os anos (por exemplo, quando uma coluna é interpretada como número em um arquivo e texto no outro) e para preservar a integridade dos códigos identificadores (mantendo zeros à esquerda).

Optou-se por manter os nomes das variáveis em seu formato original (caixa alta), sem a aplicação imediata de funções de padronização de nomenclatura (como clean_names), para assegurar a compatibilidade direta com o Dicionário de Dados oficial do SINAN nas etapas de tradução subsequentes.

Após a leitura, realizou-se a união das bases com dplyr::bind_rows(), formando um único conjunto consolidado de notificações brutas.

# Lista contendo cada ano da base
dados_sinan_lista <- list(
  readxl::read_excel("sinan_2023.xlsx", col_types = "text"),
  readxl::read_excel("sinan_2024.xlsx", col_types = "text")
)

# União dos bancos de 2023 e 2024
dados_sinan <- dplyr::bind_rows(dados_sinan_lista)

# Visualização de exemplo
DT::datatable(
  dados_sinan[1:10, c("DT_NOTIFIC", "ID_MUNICIP", "ID_UNIDADE", 
                      "DT_OCOR", "IDADE", "SEXO")],
  caption = "Amostra das 10 primeiras linhas da base SINAN (variáveis-chave)",
  options = list(pageLength = 10, dom = 'tip')
)

3.3 Padronização dos Dados

Como os dados brutos do SINAN utilizam códigos numéricos para representar categorias (ex.: “1” para “Sim”, “2” para “Não”, ou códigos específicos para locais e motivações), foi necessário realizar um processo de tradução para tornar a base legível e analiticamente útil.

Utilizando como referência o Dicionário de Dados do SINAN (Versão 5), construímos “mapas” (vetores nomeados) no R para associar cada código à sua respectiva descrição. Esse processo envolveu três estratégias principais implementadas via pacote tidyverse:

Criação de Dicionários de Tradução: Foram definidos vetores para mapear categorias gerais (como variáveis binárias de “Sim/Não/Ignorado”) e categorias específicas (como LOCAL_OCOR, VIOL_MOTIV, ORIENT_SEX, etc.). Nesta etapa, também houve padronização de inconsistências de formatação presentes nos arquivos originais (ex.: unificando os códigos “1” e “01” para a mesma categoria).

Padronização dos Tipos de Dados: Antes da tradução, todas as colunas foram convertidas para o tipo texto (character). Isso foi necessário para garantir que a função de recodificação funcionasse uniformemente, evitando erros decorrentes de colunas interpretadas como numéricas em um ano e texto no outro.

Substituição dos Códigos: Utilizando as funções mutate(), across() e recode(), aplicamos as traduções diretamente nas colunas originais.

Para as mais de 50 variáveis binárias (como VIOL_FISIC, REL_PAI, ENC_SAUDE), a tradução foi aplicada em massa.

Para variáveis com categorias únicas (como Local de Ocorrência e Motivação), a recodificação foi aplicada individualmente conforme os dicionários específicos.

library(tidyverse)

# tradução dos códigos da planilha

mapa_sim_nao <- c("1"="Sim", "2"="Não", "8"="Não se aplica", "9"="Ignorado", "99"="Ignorado")

mapa_local <- c("01"="Residência", "1"="Residência", "02"="Habitação Coletiva", "2"="Habitação Coletiva", 
                "03"="Escola", "3"="Escola", "04"="Local prática esportiva", "4"="Local prática esportiva",
                "05"="Bar ou similar", "5"="Bar ou similar", "06"="Via pública", "6"="Via pública",
                "07"="Comércio/Serviços", "7"="Comércio/Serviços", "08"="Indústria/Construção", "8"="Indústria/Construção",
                "09"="Outro", "9"="Outro", "99"="Ignorado")

mapa_orientacao <- c("1"="Heterossexual", "2"="Homossexual (gay/lésbica)", "3"="Bissexual", "8"="Não se aplica", "9"="Ignorado")
mapa_genero     <- c("1"="Travesti", "2"="Transexual mulher", "3"="Transexual homem", "8"="Não se aplica", "9"="Ignorado")

mapa_motivacao  <- c("01"="Sexismo", "1"="Sexismo", "02"="Homofobia/Lesbofobia/Transfobia", "2"="Homofobia/Lesbofobia/Transfobia",
                     "03"="Racismo", "3"="Racismo", "04"="Intolerância religiosa", "4"="Intolerância religiosa",
                     "05"="Xenofobia", "5"="Xenofobia", "06"="Conflito geracional", "6"="Conflito geracional",
                     "07"="Situação de rua", "7"="Situação de rua", "08"="Deficiência", "8"="Deficiência",
                     "09"="Outros", "9"="Outros", "88"="Não se aplica", "99"="Ignorado")

mapa_ciclo_vida <- c("1"="Criança (0-9)", "2"="Adolescente (10-19)", "3"="Jovem (20-24)", "4"="Adulto (25-59)", "5"="Idoso (60+)", "9"="Ignorado")
mapa_autor_sexo <- c("1"="Masculino", "2"="Feminino", "3"="Ambos", "9"="Ignorado")
mapa_num_envolv <- c("1"="Um", "2"="Dois ou mais", "9"="Ignorado")


# colunas que possuem "sim/não"
cols_sim_nao <- c(
  "DEF_TRANS", "DEF_FISICA", "DEF_MENTAL", "DEF_VISUAL", "DEF_AUDITI", "TRAN_MENT",
  "VIOL_FISIC", "VIOL_PSICO", "VIOL_TORT", "VIOL_SEXU", "VIOL_TRAF", 
  "VIOL_FINAN", "VIOL_NEGLI", "VIOL_INFAN",
  "AG_FORCA", "AG_ENFOR", "AG_OBJETO", "AG_CORTE", "AG_QUENTE", 
  "AG_ENVEN", "AG_FOGO", "AG_AMEACA",
  "SEX_ASSEDI", "SEX_ESTUPR", "SEX_PORNO", "SEX_EXPLO",
  "REL_PAI", "REL_MAE", "REL_PAD", "REL_MAD", "REL_CONJ", "REL_EXCON", 
  "REL_NAMO", "REL_EXNAM", "REL_IRMAO", "REL_FILHO", "REL_CONHEC", 
  "REL_DESCO", "REL_DESCO.1", "REL_PATRAO", "REL_INST", "REL_POL", "REL_TRAB",
  "ENC_SAUDE", "ASSIST_SOC", "REDE_EDUCA", "ATEND_MULH", "CONS_TUTEL", 
  "CONS_IDO", "DIR_HUMAN", "MPU", "DELEG_CRIA", "DELEG_MULH", 
  "INFAN_JUV", "DEFEN_PUBL", "DELEG_IDOS"
)

# aplicação das traduções

dados_tratados <- dados_sinan |>
  mutate(

    across(everything(), as.character),
    
    # traduz colunas de Sim/Não
    across(any_of(cols_sim_nao), ~recode(., !!!mapa_sim_nao)),
    
    # traduz as específicas (atribuindo ao mesmo nome original)
    LOCAL_OCOR = recode(LOCAL_OCOR, !!!mapa_local),
    ORIENT_SEX = recode(ORIENT_SEX, !!!mapa_orientacao),
    IDENT_GEN  = recode(IDENT_GEN, !!!mapa_genero),
    VIOL_MOTIV = recode(VIOL_MOTIV, !!!mapa_motivacao),
    CICL_VID   = recode(CICL_VID, !!!mapa_ciclo_vida),
    AUTOR_SEXO = recode(AUTOR_SEXO, !!!mapa_autor_sexo),
    NUM_ENVOLV = recode(NUM_ENVOLV, !!!mapa_num_envolv)
  )

# Visualização
DT::datatable(
  head(dados_tratados |> select(DT_NOTIFIC, VIOL_FISIC, LOCAL_OCOR, VIOL_MOTIV)),
  caption = "Base com Códigos Substituídos por Nomes",
  options = list(dom = 't')
)

3.4 Tratamento e Limpeza de NAs

Para garantir a integridade da análise, realizou-se primeiro a padronização dos campos vazios, convertendo células sem informação para o código NA.

Em seguida, aplicou-se um critério de exclusão seletiva: foram removidos da base apenas os registros que não possuíam informações essenciais para a identificação do caso, especificamente a Data de Notificação (DT_NOTIFIC) e o Município de Notificação (ID_MUNICIP). Para as demais variáveis descritivas (como raça ou motivação), optou-se por manter os dados ausentes, que serão categorizados como “Ignorado” nas análises subsequentes.

# Lista de colunas de interesse
cols_limpeza <- c(
  "DT_NOTIFIC", "ESTADO_NOTIFICACAO", "NU_ANO", "ID_MUNICIP", "ID_UNIDADE", 
  "DT_OCOR", "ANO_NASC", "IDADE", "SEXO", "CS_RACA", "SG_UF", "ID_MUNIC_RESI", 
  "ID_MN_OCOR", "LOCAL_OCOR", "ORIENT_SEX", "IDENT_GEN", "DEF_TRANS", 
  "DEF_FISICA", "DEF_MENTAL", "DEF_VISUAL", "DEF_AUDITI", "TRAN_MENT", 
  "VIOL_MOTIV", "VIOL_FISIC", "VIOL_PSICO", "VIOL_TORT", "VIOL_SEXU", 
  "VIOL_TRAF", "VIOL_FINAN", "VIOL_NEGLI", "VIOL_INFAN", "AG_FORCA", 
  "AG_ENFOR", "AG_OBJETO", "AG_CORTE", "AG_QUENTE", "AG_ENVEN", "AG_FOGO", 
  "AG_AMEACA", "SEX_ASSEDI", "SEX_ESTUPR", "SEX_PORNO", "SEX_EXPLO", 
  "NUM_ENVOLV", "AUTOR_SEXO", "CICL_VID", "REL_PAI", "REL_MAE", "REL_PAD", 
  "REL_MAD", "REL_CONJ", "REL_EXCON", "REL_NAMO", "REL_EXNAM", "REL_IRMAO", 
  "REL_FILHO", "REL_CONHEC", "REL_DESCO", "REL_DESCO.1", "REL_PATRAO", 
  "REL_INST", "REL_POL", "ENC_SAUDE", "ASSIST_SOC", "REDE_EDUCA", 
  "ATEND_MULH", "CONS_TUTEL", "CONS_IDO", "DIR_HUMAN", "MPU", "DELEG_CRIA", 
  "DELEG_MULH", "INFAN_JUV", "DEFEN_PUBL", "DELEG_IDOS", "REL_TRAB"
)

dados_finais <- dados_tratados |> 
  # padronizar: Transformar vazio ("") e espaço (" ") em NA
  mutate(
    across(any_of(cols_limpeza), ~na_if(., "")),
    across(any_of(cols_limpeza), ~na_if(., " "))
  ) |> 
  
  # filtro para remover apenas se faltar Data ou Município
  drop_na(DT_NOTIFIC, ID_MUNICIP)

# Visualizar o resultado
DT::datatable(head(dados_finais), options = list(scrollX = TRUE, dom = 't'))

Análise Exploratória

Nesta seção, investigamos os padrões da violência notificada em sua totalidade, buscando compreender as diferenças demográficas, as características das agressões e a distribuição espacial dos casos em Pernambuco, com ênfase nas disparidades de gênero e raça.

4.1 Distribuição Geral das Notificações e Volume total por ano

Esta seção estabelece a dimensão quantitativa do problema. Analisamos o volume total de notificações registradas no período, comparando a evolução entre 2023 e 2024.

# meses para garantir ordem correta
meses_pt <- c("Janeiro", "Fevereiro", "Março", "Abril", "Maio", "Junho",
              "Julho", "Agosto", "Setembro", "Outubro", "Novembro", "Dezembro")

# colunas auxiliares
dados_tempo <- dados_finais |> 
  filter(!is.na(DT_NOTIFIC)) |> 
  mutate(
    DT_NOTIFIC = lubridate::ymd(DT_NOTIFIC),
    ANO = year(DT_NOTIFIC),
    MES_NUM = month(DT_NOTIFIC),
    MES = factor(MES_NUM, levels = 1:12, labels = meses_pt, ordered = TRUE)
  )

# tabela
tabela_ano <- dados_tempo |> 
  count(ANO, name = "Total de Casos") |> 
  mutate(
    Variação = (`Total de Casos` - lag(`Total de Casos`)) / lag(`Total de Casos`),
    Variação_Formatada = scales::percent(Variação, accuracy = 0.1)
  )

print(knitr::kable(tabela_ano, caption = "Total de Notificações de Violência por Ano em PE"))
## 
## 
## Table: Total de Notificações de Violência por Ano em PE
## 
## |  ANO| Total de Casos|   Variação|Variação_Formatada |
## |----:|--------------:|----------:|:------------------|
## | 2023|           4135|         NA|NA                 |
## | 2024|           2943| -0.2882709|-28.8%             |
# grafico de barras
ggplot(dados_tempo, aes(x = factor(ANO))) +
  geom_bar(fill = "#2C3E50", width = 0.6) +
  geom_text(stat='count', aes(label=..count..), vjust=-0.5, fontface="bold", size=5) +
  labs(title = "Volume de Notificações por Ano",
       subtitle = "Comparativo absoluto (2023 vs 2024)",
       x = "Ano de Notificação",
       y = "Quantidade de Casos") +
  theme_minimal() +
  theme(
    plot.title = element_text(size = 14, face = "bold"),
    panel.grid.major.x = element_blank()
  ) +
  ylim(0, max(table(dados_tempo$ANO)) * 1.15)

4.2 Sazonalidade Mensal

Ao observar a distribuição mensal, buscamos padrões sazonais. Picos em meses específicos podem estar associados a festividades (como Carnaval ou São João) ou campanhas de conscientização (como o Março Mulher)

# agrupando dados por Mês e Ano
dados_mensal <- dados_tempo |> 
  count(ANO, MES) |> 
  mutate(ANO = factor(ANO))

# Gráfico de Linhas
ggplot(dados_mensal, aes(x = MES, y = n, group = ANO, color = ANO)) +
  geom_line(linewidth = 1.2, alpha = 0.8) +
  geom_point(size = 3) +
  scale_color_manual(values = c("2023" = "#95A5A6", "2024" = "#C0392B")) +
  labs(title = "Evolução Mensal das Notificações",
       subtitle = "Comparativo de sazonalidade e tendência mensal",
       x = "", 
       y = "Número de Notificações",
       color = "Ano") +
  theme_minimal() +
  theme(
    legend.position = "top",
    axis.text.x = element_text(angle = 45, hjust = 1),
    panel.grid.minor = element_blank()
  )

A análise temporal revela um comportamento distinto entre os dois anos. Observa-se que, durante o primeiro semestre (janeiro a junho), o ano de 2024 (linha vermelha) apresentou sistematicamente um volume de notificações superior ao registrado em 2023 (linha cinza), indicando uma tendência de crescimento dos registros no estado.

Entretanto, nota-se uma queda abrupta nas notificações de 2024 a partir de setembro. Este fenômeno não deve ser interpretado como redução real da violência, pois, considerando que o SINAN segue um fluxo hierárquico de transmissão (Unidade > Município > Estado > Federal), é esperado que os meses mais recentes da base de dados atual (2024) ainda não estejam totalmente consolidados. Portanto, a redução visualizada no gráfico deve ser interpretada com cautela, tratando-se provavalmente de dados preliminares e não de uma diminuição real da violência no período.

4.3 Perfil Demográfico

Compreender o perfil das vítimas é essencial para identificar grupos de vulnerabilidade e direcionar políticas públicas. Nesta seção, detalhamos a distribuição dos casos por sexo, raça/cor e ciclo de vida.

Preparação demográfica

mapa_sexo <- c("M" = "Masculino", "F" = "Feminino", "I" = "Ignorado")

dados_demo <- dados_finais |> 
  mutate(
    # garantia que o sexo que esteja como Masculino/Feminino
    SEXO_DESC = recode(SEXO, !!!mapa_sexo, .default = SEXO),
    
    # os vazios estão "Ignorado" 
    RACA_COR = if_else(is.na(CS_RACA) | CS_RACA == "", "Ignorado", CS_RACA),
    
    # idade
    IDADE_REAL = case_when(
      # se tiver escrito "mês", "dia" ou "hora", é bebê -> 0 anos
      str_detect(tolower(IDADE), "mês|mes|dia|hora") ~ 0,
      
      # Se tiver escrito "ano", extrai só o número
      str_detect(tolower(IDADE), "ano") ~ readr::parse_number(IDADE),
      
      # se for só número (ex: "13"), converte direto
      TRUE ~ as.numeric(IDADE)
    ),
    
    # criação de faixas etárias
    FAIXA_ETARIA = case_when(
      IDADE_REAL < 10 ~ "Criança (0-9)",
      IDADE_REAL >= 10 & IDADE_REAL < 20 ~ "Adolescente (10-19)",
      IDADE_REAL >= 20 & IDADE_REAL < 60 ~ "Adulto (20-59)",
      IDADE_REAL >= 60 ~ "Idoso (60+)",
      TRUE ~ "Ignorado"
    ),
    
    FAIXA_ETARIA = factor(FAIXA_ETARIA, 
                          levels = c("Criança (0-9)", "Adolescente (10-19)", 
                                     "Adulto (20-59)", "Idoso (60+)", "Ignorado"))
  )

Raça e sexo: Análise interssecional

# Filtrando dados
dados_raca <- dados_demo |> 
  filter(SEXO_DESC %in% c("Feminino", "Masculino"), 
         RACA_COR != "Ignorado") |> 
  count(SEXO_DESC, RACA_COR)

# Gráfico
ggplot(dados_raca, aes(x = SEXO_DESC, y = n, fill = RACA_COR)) +
  geom_col(position = "dodge") +
  geom_text(aes(label = n), position = position_dodge(width = 0.9), 
            vjust = -0.5, size = 3, fontface = "bold") +
  scale_fill_brewer(palette = "Set2") +
  labs(title = "Distribuição de Raça/Cor por Sexo",
       x = "", y = "Número de Casos", fill = "Raça/Cor") +
  theme_minimal() +
  theme(legend.position = "bottom",
        plot.title = element_text(face = "bold", size = 14))

Análise com Faixas Etárias

dados_demo |> 
  filter(FAIXA_ETARIA != "Ignorado") |> 
  count(FAIXA_ETARIA) |> 
  ggplot(aes(x = fct_rev(FAIXA_ETARIA), y = n)) +
  geom_col(fill = "#8E44AD", width = 0.7) +
  geom_text(aes(label = n), hjust = -0.2, fontface = "bold") +
  coord_flip() +
  labs(title = "Notificações por Ciclo de Vida",
       x = "", y = "Quantidade de Casos") +
  theme_minimal() +
  theme(plot.title = element_text(face = "bold", size = 14)) +
  ylim(0, nrow(dados_demo) * 0.6)

Pirâmide Etária

cores_sexo <- c("Masculino" = "#2980B9", "Feminino" = "#C0392B")

dados_piramide <- dados_demo |> 
  filter(!is.na(IDADE_REAL), SEXO_DESC %in% c("Masculino", "Feminino")) |> 
  mutate(IDADE_BIN = cut(IDADE_REAL, breaks = seq(0, 100, 5), right = FALSE)) |> 
  count(SEXO_DESC, IDADE_BIN) |> 
  mutate(n_plot = ifelse(SEXO_DESC == "Masculino", -n, n))

ggplot(dados_piramide, aes(x = IDADE_BIN, y = n_plot, fill = SEXO_DESC)) +
  geom_col(width = 0.9) +
  coord_flip() +
  scale_y_continuous(labels = abs, 
                     limits = c(min(dados_piramide$n_plot, na.rm=TRUE)*1.1, 
                                max(dados_piramide$n_plot, na.rm=TRUE)*1.1)) +
  scale_fill_manual(values = cores_sexo) +
  labs(title = "Pirâmide Etária da Violência",
       x = "Faixa Etária (5 em 5 anos)", 
       y = "Número de Notificações",
       fill = "") +
  theme_minimal() +
  theme(legend.position = "top",
        plot.title = element_text(face = "bold", size = 14))

O gráfico revela uma acentuada assimetria de gênero. O volume de notificações do sexo feminino (em vermelho) supera expressivamente o masculino (em azul) em quase todas as faixas etárias, confirmando o perfil da violência de gênero no estado.

Observa-se um padrão crítico para as mulheres a partir da faixa de 10 a 14 anos, com picos elevados durante toda a idade adulta jovem (até os 39 anos). Este comportamento sugere uma forte correlação com a violência doméstica, sexual e por parceiro íntimo, que se intensifica a partir da adolescência. Já na base da pirâmide (0 a 9 anos), a distribuição entre os sexos é mais equilibrada, indicando que, nesta fase, a violência (geralmente negligência ou física) atinge meninos e meninas de forma mais similar.

4.4 Características da Violência

Além de identificar a vítima, é necessário entender a natureza da agressão.

Tipos de Violência

# preparação dos dados
dados_tipos <- dados_finais |> 
  filter(SEXO %in% c("Masculino", "Feminino", "M", "F")) |> 
  mutate(SEXO_GRAFICO = case_when(
    str_starts(SEXO, "M") ~ "Masculino",
    str_starts(SEXO, "F") ~ "Feminino",
    TRUE ~ SEXO
  )) |>
  select(SEXO_GRAFICO, starts_with("VIOL_"), -VIOL_MOTIV) |> 
  pivot_longer(cols = -SEXO_GRAFICO, names_to = "TIPO", values_to = "RESPOSTA") |> 
  filter(RESPOSTA %in% c("Sim", "1")) |> 
  mutate(
    TIPO = str_remove(TIPO, "VIOL_"),
    TIPO = case_when(
      TIPO == "FISIC" ~ "Física",
      TIPO == "PSICO" ~ "Psicológica",
      TIPO == "SEXU" ~ "Sexual",
      TIPO == "NEGLI" ~ "Negligência/Abandono",
      TIPO == "TORT" ~ "Tortura",
      TIPO == "FINAN" ~ "Financeira",
      TIPO == "TRAF" ~ "Tráfico Humano",
      TIPO == "INFAN" ~ "Violência Infantil",
      TRUE ~ TIPO
    )
  )

# grafico
ggplot(dados_tipos, aes(x = fct_infreq(TIPO), fill = SEXO_GRAFICO)) +
  geom_bar(position = "dodge", width = 0.8, color = "white") +
  coord_flip() +
  
  scale_fill_manual(values = c("Masculino" = "#A9CCE3", "Feminino" = "#F5B7B1")) +
  
  labs(title = "Tipos de Violência mais Notificados",
       subtitle = "Comparativo por Gênero",
       x = "", 
       y = "Quantidade de Notificações", 
       fill = "") +
  theme_minimal() +
  theme(
    legend.position = "top",
    plot.title = element_text(face = "bold", size = 14),
    axis.text.y = element_text(size = 11)
  )

Meios de Agressão

dados_meios <- dados_finais |> 
  filter(SEXO %in% c("Masculino", "Feminino", "M", "F")) |> 
  mutate(SEXO_GRAFICO = case_when(
    str_starts(SEXO, "M") ~ "Masculino", 
    str_starts(SEXO, "F") ~ "Feminino",
    TRUE ~ SEXO
  )) |>
  select(SEXO_GRAFICO, starts_with("AG_")) |> 
  pivot_longer(cols = -SEXO_GRAFICO, names_to = "MEIO", values_to = "RESPOSTA") |> 
  filter(RESPOSTA %in% c("Sim", "1")) |> 
  mutate(
    MEIO = str_remove(MEIO, "AG_"),
    MEIO = case_when(
      MEIO == "FORCA" ~ "Força Corporal",
      MEIO == "ENFOR" ~ "Enforcamento",
      MEIO == "OBJETO" ~ "Objeto Contundente",
      MEIO == "CORTE" ~ "Perfurocortante",
      MEIO == "QUENTE" ~ "Substância Quente",
      MEIO == "ENVEN" ~ "Envenenamento",
      MEIO == "FOGO" ~ "Arma de Fogo",
      MEIO == "AMEACA" ~ "Ameaça",
      TRUE ~ MEIO
    )
  )

# grafico
ggplot(dados_meios, aes(x = fct_infreq(MEIO), fill = SEXO_GRAFICO)) +
  geom_bar(position = "stack", width = 0.7) +

  scale_fill_manual(values = c("Masculino" = "#A9CCE3", "Feminino" = "#F5B7B1")) +
  
  labs(title = "Meios de Agressão Utilizados",
       subtitle = "Volume total por instrumento",
       x = "", 
       y = "Total de Ocorrências", 
       fill = "") +
  theme_minimal() +
  theme(
    legend.position = "top",
    axis.text.x = element_text(angle = 45, hjust = 1)
  )

4.5 Contexto da ocorrência

Nesta etapa, foi analisada o local onde a agressão ocorreu e o vínculo entre a vítima e o provável autor, dados essenciais para distinguir a violência doméstica daquela urbana ou comunitária.

Local da Violência

O gráfico abaixo compara os locais de ocorrência.

# escolhi 5 locais mais frequentes para limpar o gráfico
top_locais <- dados_finais |> 
  filter(SEXO %in% c("Masculino", "Feminino", "M", "F")) |> 
  count(LOCAL_OCOR, sort = TRUE) |> 
  slice(1:5) |> 
  pull(LOCAL_OCOR)

dados_local <- dados_finais |> 
  filter(LOCAL_OCOR %in% top_locais,
         SEXO %in% c("Masculino", "Feminino", "M", "F")) |> 
  mutate(SEXO_GRAFICO = case_when(
    str_starts(SEXO, "M") ~ "Masculino", 
    str_starts(SEXO, "F") ~ "Feminino",
    TRUE ~ SEXO
  ))

# gráfico
ggplot(dados_local, aes(x = fct_infreq(LOCAL_OCOR), fill = SEXO_GRAFICO)) +
  geom_bar(position = "dodge", width = 0.8, color = "white") +

  scale_fill_manual(values = c("Masculino" = "#A9CCE3", "Feminino" = "#F5B7B1")) +
  
  labs(title = "Local de Ocorrência da Violência",
       subtitle = "Espaço público vs. Espaço privado",
       x = "", 
       y = "Quantidade de Casos", 
       fill = "") +
  theme_minimal() +
  theme(
    legend.position = "top",
    plot.title = element_text(face = "bold", size = 14),
    axis.text.x = element_text(size = 11)
  )

Perfil do Agressor: Qual era o vínculo com a vítima?

# preparação dos dados
dados_vinculo <- dados_finais |> 
  mutate(
    SEXO_GRAFICO = case_when(
      str_starts(SEXO, "M") | SEXO == "1" ~ "Vítimas: Homens",
      str_starts(SEXO, "F") | SEXO == "2" ~ "Vítimas: Mulheres",
      TRUE ~ NA_character_
    )
  ) |>
  filter(!is.na(SEXO_GRAFICO)) |> 
  mutate(
    VINCULO_RESUMO = case_when(
      REL_CONJ %in% c("Sim", "1") | REL_NAMO %in% c("Sim", "1") ~ "Parceiro Íntimo",
      REL_EXCON %in% c("Sim", "1") | REL_EXNAM %in% c("Sim", "1") ~ "Ex-Parceiro",
      REL_PAI %in% c("Sim", "1") | REL_MAE %in% c("Sim", "1") | 
      REL_PAD %in% c("Sim", "1") | REL_MAD %in% c("Sim", "1") ~ "Pais/Padrastos",
      REL_FILHO %in% c("Sim", "1") | REL_IRMAO %in% c("Sim", "1") ~ "Irmão/Filho",
      REL_CONHEC %in% c("Sim", "1") ~ "Amigo/Conhecido",
      REL_PATRAO %in% c("Sim", "1") | REL_TRAB %in% c("Sim", "1") ~ "Patrão/Colega",
      REL_POL %in% c("Sim", "1") ~ "Policial/Agente",
      REL_DESCO %in% c("Sim", "1") ~ "Desconhecido",
      TRUE ~ NA_character_
    )
  ) |> 
  filter(!is.na(VINCULO_RESUMO))

# grafico
ggplot(dados_vinculo, aes(x = fct_infreq(VINCULO_RESUMO), fill = SEXO_GRAFICO)) +
  geom_bar(width = 0.7, show.legend = FALSE) +
  coord_flip() + 
  
  # Separa em dois gráficos lado a lado
  facet_wrap(~SEXO_GRAFICO, scales = "free_x") + 
  
  scale_fill_manual(values = c("Vítimas: Homens" = "#A9CCE3", "Vítimas: Mulheres" = "#F5B7B1")) +
  
  labs(title = "Quem comete a violência?",
       subtitle = "Perfil do agressor segundo o sexo da vítima",
       x = "", 
       y = "Número de Notificações") +
  theme_minimal() +
  theme(
    plot.title = element_text(face = "bold", size = 14),
    strip.text = element_text(face = "bold", size = 12), # Aumenta o título de cada painel
    axis.text.y = element_text(size = 10)
  )

Número de envolvidos

dados_finais |> 
  filter(SEXO %in% c("Masculino", "Feminino", "M", "F"),
         !is.na(NUM_ENVOLV), NUM_ENVOLV != "Ignorado") |> 
  mutate(SEXO_GRAFICO = case_when(str_starts(SEXO, "M") ~ "Masculino", TRUE ~ "Feminino")) |> 
  
  ggplot(aes(x = NUM_ENVOLV, fill = SEXO_GRAFICO)) +
  geom_bar(position = "fill", width = 0.6) +
  
  scale_y_continuous(labels = scales::percent) +
  scale_fill_manual(values = c("Masculino" = "#A9CCE3", "Feminino" = "#F5B7B1")) +
  
  labs(title = "Agressão Individual vs. Coletiva",
       subtitle = "Proporção de casos com um ou mais agressores",
       x = "Número de Envolvidos", 
       y = "Proporção (%)", 
       fill = "") +
  theme_minimal()

4.6 Análises Temporais

Além de saber quem são as vítimas e onde ocorrem os casos, é fundamental entender quando a violência acontece. Investigamos a distribuição das notificações ao longo dos dias da semana para identificar padrões comportamentais associados ao lazer, ao consumo de álcool e à convivência familiar.

Dia da semana

O gráfico abaixo apresenta a curva de notificações de domingo a sábado. Picos aos finais de semana são fortes indicativos de violência associada ao convívio social ou doméstico intensificado.

#  preparação com DT_OCOR (Ocorrência) para ver quando a violência aconteceu de fato
dados_temporal <- dados_finais |> 
  filter(!is.na(DT_OCOR)) |> 
  mutate(
    SEXO_GRAFICO = case_when(
      str_starts(SEXO, "M") | SEXO == "1" ~ "Masculino",
      str_starts(SEXO, "F") | SEXO == "2" ~ "Feminino",
      TRUE ~ NA_character_
    )
  ) |> 
  filter(!is.na(SEXO_GRAFICO)) |> 
  
  mutate(
    # dia da semana como fator
    DIA_SEMANA = wday(DT_OCOR, label = TRUE, abbr = FALSE, week_start = 1),
    
    # fator Fim de Semana
    TIPO_DIA = case_when(
      DIA_SEMANA %in% c("sábado", "domingo") ~ "Final de Semana",
      TRUE ~ "Dia Útil"
    )
  )

# grafico
dados_temporal |> 
  count(DIA_SEMANA, SEXO_GRAFICO) |> 
  ggplot(aes(x = DIA_SEMANA, y = n, group = SEXO_GRAFICO, color = SEXO_GRAFICO)) +
  geom_line(linewidth = 1.5, alpha = 0.8) +
  geom_point(size = 4) +
  
  scale_color_manual(values = c("Masculino" = "#76D7C4", "Feminino" = "#C39BD3")) +
  
  labs(title = "Quando a violência acontece?",
       subtitle = "Ocorrências por dia da semana (Data do Fato)",
       x = "", 
       y = "Número de Casos", 
       color = "") +
  theme_minimal() +
  theme(
    legend.position = "top",
    plot.title = element_text(face = "bold", size = 14),
    panel.grid.minor = element_blank(),
    axis.text.x = element_text(size = 11)
  )

Fim de semana vs. Dia útil

# Gráfico
# usando dados_temporal (anterior)
ggplot(dados_temporal, aes(x = TIPO_DIA, fill = SEXO_GRAFICO)) +
  geom_bar(position = "dodge", width = 0.6, color = "white") + 
  
  scale_fill_manual(values = c("Masculino" = "#76D7C4", "Feminino" = "#C39BD3")) +
  
  labs(title = "Violência: Dias Úteis vs. Final de Semana",
       subtitle = "Comparativo de volume de notificações (Data da Ocorrência)",
       x = "", 
       y = "Total de Ocorrências", 
       fill = "") +
  theme_minimal() +
  theme(
    legend.position = "top",
    plot.title = element_text(face = "bold", size = 14),
    axis.text.x = element_text(size = 12, face = "bold")
  )

Os dados demonstram que, embora os dias úteis acumulem um volume absoluto considerável de registros, a densidade de violência (intensidade por dia) é significativamente maior aos finais de semana. Observa-se uma escalada de ocorrências que se inicia nas sextas-feiras e atinge seu ápice aos sábados e domingos. Este comportamento sugere uma forte correlação entre a violência e momentos de convivência familiar intensificada e atividades de lazer, frequentemente associados ao consumo de álcool.

4.7 Análises Espaciais

Utilizando técnicas de geoprocessamento, irei mapear a concentração de casos pelos municípios de Pernambuco. Esta visualização permite identificar as áreas de maior incidência e apoiar a distribuição de recursos considerando as especificidades regionais.

Mapa de calor

library(geobr)
library(stringi)

# baixar Mapa
mapa_pe <- geobr::read_municipality(code_muni = "PE", year = 2020, showProgress = FALSE)

# padronização
mapa_tratado <- mapa_pe |> 
  mutate(CHAVE = name_muni |> toupper() |> stri_trans_general("Latin-ASCII"))

dados_geo <- dados_finais |> 
  filter(!is.na(ID_MUNICIP)) |> 
  mutate(CHAVE = as.character(ID_MUNICIP) |> toupper() |> stri_trans_general("Latin-ASCII")) |> 
  count(CHAVE, name = "Total_Casos")

# merge
mapa_final <- mapa_tratado |> 
  left_join(dados_geo, by = "CHAVE") |> 
  # substitui NA por 0 para não ficar buraco no mapa
  mutate(Total_Casos = replace_na(Total_Casos, 0))

# plot
ggplot(mapa_final) +
  geom_sf(aes(fill = Total_Casos), color = "white", size = 0.1) +
  
  # Escala de cor Logarítmica
  scale_fill_viridis_c(option = "rocket", direction = -1, 
                       name = "Casos", 
                       trans = "log10",
                       labels = scales::comma) +
  
  labs(title = "Distribuição Espacial da Violência em PE",
       subtitle = "Volume total de notificações (2023-2024)",
       caption = "Fonte: SINAN/DATASUS | Elaboração própria") +
  
  theme_void() +
  theme(
    legend.position = "bottom",
    plot.title = element_text(face = "bold", size = 16, hjust = 0.5),
    plot.subtitle = element_text(hjust = 0.5, color = "grey30")
  )

O mapa de calor evidencia uma forte concentração de notificações na faixa litorânea, correspondente à Região Metropolitana do Recife (RMR), área de maior densidade demográfica do estado.

Entretanto, a interiorização da violência é visível através dos polos regionais. Municípios-chave como Caruaru (Agreste) e Petrolina (Sertão do São Francisco) destacam-se como hotspots de notificação fora da capital. As áreas mais claras podem indicar municípios com menor população ou, em alguns casos, onde a rede de saúde pode não estar captando ou notificando adequadamente os casos existentes.

Ranking com maior volume de Notificações

# usando mapa_final
ranking_mun <- mapa_final |> 
  sf::st_drop_geometry() |> # remove o desenho do mapa para virar uma tabela leve
  filter(Total_Casos > 0) |>
  arrange(desc(Total_Casos)) |> # ordenação
  slice(1:15) # top 15

# grafico
ggplot(ranking_mun, aes(x = reorder(name_muni, Total_Casos), y = Total_Casos)) +
  geom_col(fill = "#C0392B", width = 0.7) +
  
  # nuemero total das notif na ponta da barra
  geom_text(aes(label = Total_Casos), hjust = -0.1, size = 3.5, fontface = "bold") +
  
  coord_flip() +
  labs(title = "Os 15 municípios com maior Volume de Violência (Notificações)",
       x = "", 
       y = "Número de Notificações") +
  
  theme_minimal() +
  theme(
    plot.title = element_text(face = "bold", size = 14),
    axis.text.y = element_text(face = "bold", size = 10)
  ) +
  ylim(0, max(ranking_mun$Total_Casos) * 1.15)

4.8 O Fator Racial nas Notificações de Violência

A análise da violência não pode ser dissociada dos marcadores sociais. Nesta seção, investigamos a distribuição das notificações segundo a raça/cor autodeclarada, garantindo a visibilidade de todos os grupos étnico-raciais presentes no estado.

Distribuição Racial Completa

O gráfico abaixo compara o volume de notificações entre os grupos raciais. Destacamos a população negra (soma de pretos e pardos), mas também observamos a incidência nas populações branca, amarela e indígena.

dados_raca_analise <- dados_finais |> 
  mutate(
    # padronização
    CS_RACA_STR = str_trim(as.character(CS_RACA)),
    
    RACA_COR = case_when(
      CS_RACA_STR %in% c("1", "01") ~ "Branca",
      CS_RACA_STR %in% c("2", "02") ~ "Preta",
      CS_RACA_STR %in% c("3", "03") ~ "Amarela",
      CS_RACA_STR %in% c("4", "04") ~ "Parda",
      CS_RACA_STR %in% c("5", "05") ~ "Indígena",

      str_detect(tolower(CS_RACA_STR), "branca") ~ "Branca",
      str_detect(tolower(CS_RACA_STR), "parda") ~ "Parda",
      str_detect(tolower(CS_RACA_STR), "preta") ~ "Preta",
      str_detect(tolower(CS_RACA_STR), "amarela") ~ "Amarela",
      str_detect(tolower(CS_RACA_STR), "indigena|indígena") ~ "Indígena",
      
      TRUE ~ "Ignorado"
    ),
    
    CATEGORIA_RACA = case_when(
      RACA_COR %in% c("Preta", "Parda") ~ "Negra (Preta + Parda)",
      RACA_COR == "Branca" ~ "Branca",
      RACA_COR == "Amarela" ~ "Amarela",
      RACA_COR == "Indígena" ~ "Indígena",
      TRUE ~ "Ignorado"
    )
  ) |> 
  filter(CATEGORIA_RACA != "Ignorado") # remove ignorados

# grafico
ggplot(dados_raca_analise, aes(x = fct_infreq(CATEGORIA_RACA), fill = CATEGORIA_RACA)) +
  geom_bar(width = 0.7) +
  geom_text(aes(label = ..count..), stat = "count", vjust = -0.5, fontface = "bold") +
  
  scale_fill_manual(values = c(
    "Negra (Preta + Parda)" = "#8da0cb", 
    "Branca" = "#fc8d62",                
    "Amarela" = "#ffd92f",               
    "Indígena" = "#66c2a5"               
  )) +
  
  labs(title = "Perfil Racial das Vítimas de Violência",
       subtitle = "Notificações segundo autodeclaração de raça/cor",
       x = "", 
       y = "Número de Casos",
       fill = "Grupo Racial") +
  theme_minimal() +
  theme(
    plot.title = element_text(face = "bold", size = 14),
    legend.position = "none"
  )

Os dados analisados expõem a centralidade da raça na dinâmica da violência em Pernambuco. A população negra (preta e parda) não apenas representa a maioria absoluta das notificações, refletindo a demografia do estado, mas também apresenta padrões específicos de vitimização

Tipologia por raça: A natureza da violência muda conforme a cor da pele?

dados_raca_tipos <- dados_raca_analise |> 
  select(CATEGORIA_RACA, starts_with("VIOL_"), -VIOL_MOTIV) |> 
  pivot_longer(cols = starts_with("VIOL_"), names_to = "TIPO", values_to = "RESPOSTA") |> 
  filter(RESPOSTA %in% c("Sim", "1")) |> 
  mutate(
    TIPO = str_remove(TIPO, "VIOL_"),
    TIPO = case_when(
      TIPO == "FISIC" ~ "Física",
      TIPO == "PSICO" ~ "Psicológica",
      TIPO == "SEXU" ~ "Sexual",
      TIPO == "NEGLI" ~ "Negligência",
      TRUE ~ NA_character_
    )
  ) |> 
  filter(!is.na(TIPO))

# grafico
ggplot(dados_raca_tipos, aes(x = TIPO, group = CATEGORIA_RACA, fill = CATEGORIA_RACA)) +
  
  geom_bar(aes(y = after_stat(prop)), position = "dodge", width = 0.7) +
  
  scale_y_continuous(labels = scales::percent) +
  scale_fill_manual(values = c("Negra (Preta + Parda)" = "#8da0cb", "Branca" = "#fc8d62", 
                               "Amarela" = "#ffd92f", "Indígena" = "#66c2a5")) +
  
  labs(title = "Natureza da Violência: Comparativo Racial",
       subtitle = "Como cada tipo de violência afeta proporcionalmente cada grupo",
       x = "", y = "Proporção (%)", fill = "Grupo Racial") +
  theme_minimal() +
  theme(
    plot.title = element_text(face = "bold", size = 14),
    legend.position = "top",
    axis.text = element_text(size = 11)
  ) 

Ao comparar a natureza da violência, observa-se que a violência física e a negligência afetam desproporcionalmente a população negra (barra azul). Este dado sugere uma correlação com a vulnerabilidade social, onde a agressão direta e o desamparo são as formas mais prevalentes de violação de direitos.

Por outro lado, a violência psicológica apresenta uma proporção ligeiramente maior entre a população branca (barra laranja) comparada aos outros tipos. Isso pode indicar não uma ausência desse sofrimento na população negra, mas sim uma desigualdade no acesso ao diagnóstico: vítimas brancas podem ter maior facilidade em ter suas queixas de sofrimento mental reconhecidas e notificadas pelo sistema de saúde, enquanto para a população negra, muitas vezes, apenas a violência física visível é registrada.

Conclusão

Referências