Verificando afirmações com dados abertos

Uma forma poderosa de participar socialmente é utilizando dados abertos. Dados abertos tornam a sociedade mais democrática pois com eles podemos verificar afirmações baseadas em estatísticas e também buscar novas narrativas para os fenômenos estudados.

Nesse post, mostramos um exemplo de como isso pode ser feito, utilizando os dados da Sistema Nacional de Informações de Segurança pública, o SINESP. O objetivo com esse texto é empoderar as pessoas que trabalham com ciência de dados e mostrar como podemos participar socialmente usando o R.

No dia 16/julho o Ministro da Justiça, Sérgio Moro, fez a seguinte declaração no Twitter:

O legal de existirem dados abertos é que podemos checar esses informações e criar análises mais aprofundadas sobre o tema. Infelizmente, ainda não foram disponibilizados os dados do primeiro bimestre de 2019, que fazem parte do Tweet do Moro.

Mas isso não é um problema, pois podemos fazer diversos cruzamentos com os dados que estão disponíveis. Nesta rápida análise, mostro como baixar os dados a partir do portal de dados abertos https://dados.gov.br. Para isso, utilizarei o tidyverse, httr e xml2.

library(tidyverse)

Parte 1: Download

Como o dados.gov.br é um portal muito bem feito, é possível baixar todos os dados em CSV com um pipeline simples:

# caminho do diretório
path_sinesp <- "~/data-raw/sinesp/"
# cria o diretório
fs::dir_create(path_sinesp)

# link do SINESP no dados.gov.br
u_sinesp <- paste0("http://dados.gov.br/dataset",
                   "/sistema-nacional-de-estatisticas-de-seguranca-publica")

u_sinesp %>%
  # carrega a página
  httr::GET() %>%
  # parseia o código fonte da página
  xml2::read_html() %>%
  # identifica todas as tags que contêm os links
  xml2::xml_find_all("//ul[@class='dropdown-menu']//a") %>%
  # extrai a lista todos os links
  xml2::xml_attr("href") %>%
  # seleciona apenas os arquivos xlsx da lista
  str_subset("xlsx") %>%
  # essa parte faz o loop de download. Demora ~1 minuto
  walk(~httr::GET(.x, httr::write_disk(paste0(path_sinesp, basename(.x)))))

Nada impede o usuário de baixar esses arquivos CSV manualmente. Pode ser até que seja mais rápido baixar manualmente se for uma vez só. A vantagem desse código é que ele é reprodutível, a menos que o site mude sua estrutura. Ou seja, quando chegarem os dados de 2019, provavelmente poderemos baixar tudo novamente usando o mesmo código.

Parte 2: Importação e arrumação

O código abaixo carrega e arruma os dados para análise. Sempre existem inconsistências nos dados e devemos ficar atentos a eles.

d_sinesp <- path_sinesp %>% 
  # lista os arquivos
  fs::dir_ls() %>%
  # lê todos os arquivos xlsx e empilha
  map_dfr(readxl::read_excel, col_types = "text", .id = "file") %>%
  # define os nomes das colunas
  set_names(c("file", "uf", "tipo_crime", "mes_ano", "valor")) %>%
  # transforma os valores para os tipos corretos
  transmute(
    uf,
    # transformando string em data
    mes_ano = lubridate::dmy(paste0("01/", mes_ano)),
    # arrumando tipo de crime
    tipo_crime = str_to_title(tipo_crime),
    valor = as.numeric(valor),
    # cria uma coluna com o bimestre
    bimestre = lubridate::floor_date(mes_ano, "bimonth")
  )

No caso, o maior problema era um tipo de crime que estava escrito com nomes ligeiramente diferentes. Um stringr::str_to_title() foi suficiente para resolver. A base de dados ficou assim:

uf mes_ano tipo_crime valor bimestre
Acre 2015-01-01 Estupro 6 2015-01-01
Acre 2015-01-01 Furto De Veículo 0 2015-01-01
Acre 2015-01-01 Homicídio Doloso 13 2015-01-01
Acre 2015-01-01 Lesão Corporal Seguida De Morte 0 2015-01-01
Acre 2015-01-01 Roubo A Instituição Financeira 0 2015-01-01
Acre 2015-01-01 Roubo De Carga 0 2015-01-01
Acre 2015-01-01 Roubo De Veículo NA 2015-01-01
Acre 2015-01-01 Roubo Seguido De Morte (Latrocínio) 0 2015-01-01
Acre 2015-01-01 Tentativa De Homicídio 2 2015-01-01
Acre 2015-02-01 Estupro 8 2015-01-01

Parte 3: Transformação

Nesse código, meu objetivo foi reproduzir a tabela do Ministro da Justiça, mas adicionando as mudanças ocorridas entre 2015-2016, 2016-2017 e 2017-2018. Não fiz a análise por trimestre, e sim por bimestre. O leitor interessado pode replicar as análises para trimestres.

results <- d_sinesp %>%
  # agrupa por bimestre e sumariza
  group_by(bimestre, tipo_crime) %>%
  summarise(valor = sum(valor, na.rm = TRUE)) %>%
  ungroup() %>%
  # apenas primeiro bimestre e tirar dados de antes de 2015
  filter(lubridate::month(bimestre) == 1,
         lubridate::year(bimestre) >= 2015) %>%
  # ordenar e agrupar por tipo de crime
  arrange(tipo_crime, bimestre) %>%
  group_by(tipo_crime) %>%
  # adicionar bimestre anterior
  mutate(vl_lag = lag(valor)) %>%
  ungroup() %>%
  # tirar 2015
  filter(!is.na(vl_lag)) %>%
  # calcula a razão
  mutate(razao = scales::percent(valor / vl_lag - 1),
         bim1 = lubridate::year(bimestre)) %>%
  # seleciona as colunas importantes
  select(bim1, tipo_crime, razao) %>%
  # joga os bimestres nas colunas
  spread(bim1, razao, sep = "_")

knitr::kable(results)
tipo_crime bim1_2016 bim1_2017 bim1_2018
Estupro 4.3% 1.2% 11.5%
Furto De Veículo 5.5% -7.3% -6.4%
Homicídio Doloso 3.3% 6.5% -10.6%
Lesão Corporal Seguida De Morte 21.6% 23.0% -7.8%
Roubo A Instituição Financeira -4.8% -28.9% -1.4%
Roubo De Carga -1.5% 13.1% 11.2%
Roubo De Veículo 9.8% 7.0% -5.9%
Roubo Seguido De Morte (Latrocínio) 12.5% 13.7% -13.1%
Tentativa De Homicídio -7.7% -2.0% -9.9%

A tabela mostra que o primeiro bimestre de 2018, se comparado ao de 2017, também apresenta quedas em todos os tipos de crime, com exceção de estupro e roubo de cargas. Além disso, como será possível ver no próximo gráfico, as variações percentuais acima de 20% na tabela ocorrem em crimes com pequeno volume absoluto de ocorrências. Isso é esperado, pois quando o valor absoluto é pequeno, pequenas mudanças podem significar grandes variações percentuais. Por exemplo, se uma contagem vai de 150 para 120 (queda de 30), a queda é de 20%, mas se outra contagem vai de 1000 para 900 (queda de 100), a queda percentual é de 10%

Parte 4: Visualização

Nesse gráfico, mostrei a série bimestral de ocorrências por tipo de crime, buscando identificar tendências de subida ou queda.

d_sinesp %>%
  # soma por bimestre e tipo de crime
  group_by(bimestre, tipo_crime) %>%
  summarise(valor = sum(valor, na.rm = TRUE)) %>%
  ungroup() %>%
  # apenas 2015 para frente
  filter(lubridate::year(bimestre) >= 2015) %>%
  # monta o grafico
  ggplot(aes(x = bimestre, y = valor)) +
  # adiciona linhas
  geom_line() +
  # adiciona uma linha vertical par 2018
  geom_vline(xintercept = as.Date("2018-01-01"), colour = "red", linetype = 2) +
  # divide o grafico por tipo de crime
  facet_wrap(~tipo_crime, scales = "free_y", ncol = 3) +
  theme_bw()

Pelo gráfico, é possível identificar que, em diversos tipos de crime, existe uma tendência de queda após o primeiro bimestre de 2018. Ou seja, não se pode atribuir a queda nas estatísticas de ocorrências ao novo governo de 2019. A queda vertiginosa no volume de estupros é bem curiosa.

Wrap-up

  • Dado aberto é a melhor forma de tornar as informações disponibilizadas publicamente auditáveis.
  • Com o R, é fácil ingerir esses dados para realizar análises simples e complexas.
  • Não se engane: dado aberto não é dado arrumado. O trabalho de faxina de dados é contínuo.

É isso. Happy coding ;)

comments powered by Disqus