Download e tratamento de dados das eleições brasileiras usando R

elections
R
Author

Artur Quirino

Published

February 6, 2023

Modified

February 19, 2023

Nesta postagem, eu descrevo uma abordagem para download, leitura e tratamento de dados das eleições brasileiras no R, em poucas linhas de código. A atividade é desenvolvida com dados do perfil do eleitorado, detalhes da votação por seção e votação nominal por zona.

Download e leitura dos dados

Há duas formas para download e leitura das tabelas de dados do TSE no R. A primeira, querer a identificação e manuseio do link de cada tabela; a segunda, baseia-se nas funções do pacote electionsBR. A primeira opção é mais rápida, a segunda é mais simples.

No exemplo a seguir, eu faço o download das tabelas das eleições gerais estaduais de 2022, manualmente. O objeto files armazena o nome e o local onde cada arquivo foi salvo.

Download

remotes::install_github("arturhgq/dtools")

# Lista de links
urls = list(
  eleitorado2022 = paste0("https://cdn.tse.jus.br/estatistica/sead/odsele/perfil_eleitorado/perfil_eleitorado_2022.zip"),
  votacao_detalhes_secao2022 = paste0("https://cdn.tse.jus.br/estatistica/sead/odsele/detalhe_votacao_secao/detalhe_votacao_secao_2022.zip"),
  votacao_nominal_zona2022 = paste0("https://cdn.tse.jus.br/estatistica/sead/odsele/votacao_candidato_munzona/votacao_candidato_munzona_2022.zip")
)

# Download dos arquivos
files = dtools::download.files(urls)

Leitura

De posse do vetor com o caminho absoluto de cada arquivo, o fragmento de código abaixo é suficiente para ler todas as tabelas de uma vez. Na segunda aba, eu ofereço uma alternativa, com o pacote electionsBR.

data = mapply(
  dtools::read_delim_zip, 
  x = files, 
  pattern = c(".csv$", "BRASIL.csv$", "BRASIL.csv$"),
  SIMPLIFY = FALSE
)
remotes::install_github("silvadenisson/electionsBR")

year = 2022

voter_profile = electionsBR::voter_profile(year)
details_mun_zone_fed = electionsBR::details_mun_zone_fed(year, br_archive = TRUE)
vote_mun_zone_fed = electionsBR::vote_mun_zone_fed(year, br_archive = TRUE)

Em detalhes, mapply aplica à função read_delim_zip dois parâmetros: x e pattern. Em x, atribui-se o caminho absoluto dos três arquivos de interesse - “eleitorado2022”, “votacao_detalhes_secao2022” e “votacao_nominal_zona2022.” Em pattern, define-se, via regex, o padrão de arquivos que deverá ser descompactado e lido para cada x. Quanto mais detalhado for o padrão definido, menores serão os gastos com tempo e com memória RAM.

Vejamos, por exemplo, o arquivo “votacao_nominal_zona2022”. Internamente, ele contém 29 tabelas em .csv e um documento em .pdf. Portanto, caso fosse atribuido a pattern apenas o valor '.csv$', a função read_delim_zip leria e descompactaria 29 tabelas. O padrão 'BRASIL.csv'$, em contraste, seleciona apenas a tabela de interesse, que contém os dados de votacao nominal, a nível de município e zona eleitoral, dos 26 estados, do Distrito Federal e dos eleitores que votaram no exterior.

Abordagem de leitura de dados para redução de gasto de memória RAM

Certamente, se você não usa um supercomputador, carregar milhares de linhas de dados na memória do seu computador será sempre um desafio. No exemplo acima, eu consumi 9,14 GB1 de memória RAM para carregar 16.818.896 linhas de dados distribuídas em 95 colunas.

Uma opção para tornar viável a leitura de grandes volumes de dados sem estourar a memória RAM de sua máquina é carregar uma tabela de cada vez, tratar os dados da tabela carregada e somente então ler o próximo arquivo, reescrevendo o anterior. Em casos extremos, você pode particionar as tabelas ou selecionar colunas antes de carregá-las. Feito dessa forma, você poupará tempo e memória RAM.

Tratamento dos dados

Nesta seção, eu aplico as sugestões que propus no tópico anterior e faço até três operações em cada uma das tabelas: subset, agrupamento e soma. Para reduzir o consumo de tempo das operações, optei pelo pacote data.table ao em vez do amigável dplyr.

## Lista de parâmetros usados nas operações
params = list(
    by_eleitorado2022 = c(
    "SG_UF", "CD_MUNICIPIO", "NM_MUNICIPIO", "DS_GENERO", "DS_FAIXA_ETARIA", 
    "DS_GRAU_ESCOLARIDADE", "ANO_ELEICAO"
  ),
  vars_eleitorado2022 = c(
    "QT_ELEITORES_PERFIL", "QT_ELEITORES_BIOMETRIA"
  ),
  by_detalhes_votacao2022 = c(
    "DS_CARGO", "NR_TURNO", "SG_UF", "SG_UE", "NM_MUNICIPIO", "CD_MUNICIPIO",
    "ANO_ELEICAO"
  ),
  vars_detalhes_votacao2022 = c(
    "QT_APTOS", "QT_COMPARECIMENTO","QT_ABSTENCOES", "QT_VOTOS_BRANCOS",
    "QT_VOTOS_NULOS", "QT_VOTOS_NOMINAIS", "QT_VOTOS_LEGENDA"
  ),
    by_votacao2022 = c(
    "NR_TURNO", "SG_UF", "NM_MUNICIPIO", "CD_MUNICIPIO", "NR_CANDIDATO",
    "NM_CANDIDATO", "NR_PARTIDO", "SG_PARTIDO", "NM_PARTIDO", "ANO_ELEICAO"
  ),
  vars_votacao2022 = c(
    "QT_VOTOS_NOMINAIS"
  )
)

Perfil do eleitorado brasileiro (2022)

## Define as variáveis que serão carregadas
select = c(params$by_eleitorado2022, params$vars_eleitorado2022)

## Leitura dos dados
data = dtools::read_delim_zip(
  files$eleitorado2022,
  pattern = ".csv",
  col_select = select
)

## Tratamento dos dados
eleitorado_mun2022 = data.table::setDT(data)[
    , # seleciona todas as linhas
    lapply(.SD, sum), # soma todas as colunas contidas em .SD
    by = eval(params$by_eleitorado2022), # define o agrupamento
    .SDcols = params$vars_eleitorado2022 # define as colunas de .SD
  ] 

Detalhes da votação por município e zona eleitoral (2022)

## Define as variáveis que serão carregadas
select = c(
  params$by_detalhes_votacao2022, 
  params$vars_detalhes_votacao2022, 
  "DS_CARGO"
)

## Leitura dos dados
data = dtools::read_delim_zip(
  files$votacao_detalhes_secao2022,
  pattern = "BRASIL.csv",
  col_select = select
)

## Tratamento dos dados
votacao_detalhes_mun2022 = data.table::setDT(data)[
    DS_CARGO == "PRESIDENTE",
    lapply(.SD, sum), 
    by = eval(params$by_detalhes_votacao2022),
    .SDcols = params$vars_detalhes_votacao2022
  ] 

Votação nominal por município e zona eleitoral

## Define as variáveis que serão carregadas
select = c(
  params$by_votacao2022,
  params$vars_votacao2022, 
  "DS_CARGO"
)

## Leitura dos dados
data = dtools::read_delim_zip(
  files$votacao_nominal_zona2022,
  pattern = "BRASIL.csv",
  col_select = select
)

## Tratamento dos dados
votacao_mun2022 = data.table::setDT(data)[
    DS_CARGO == "Presidente",
    lapply(.SD, sum), 
    by = eval(params$by_votacao2022),
    .SDcols = params$vars_votacao2022
  ] 

Limpeza do ambiente global e da memória

Como resultado da abordagem proposta, o total de memória gasta diminuiu de 9,14 GB para 1,29 GB. Caso precise reduzir ainda mais o consumo de memória, exclua a última tabela carregada no ambiente global e resete a sessão do R. Com essas operações, houve uma nova redução no consumo de memória de 932 mb.

rm(data) # exclui a base original
.rs.restartR() # reinicia a sessão do R, mas mantém os objetos salvos no "Global Environment"

Exportando os resultados

## Lista com as tabelas tratadas
data = list(
  eleitorado_mun2022, 
  votacao_detalhes_mun2022, 
  votacao_mun2022
)

## Nome dos arquivos que serão exportados
names = c(
  "eleitorado_mun2022.csv", 
  "votacao_detalhes_mun2022.csv",
  "votacao_mun2022.csv"
)

invisible(
  mapply(
    vroom::vroom_write, 
    x = data, 
    file = here::here(names),
    delim = ";",
    bom = TRUE
  )
) 

Footnotes

  1. Por diferentes fatores, o consumo de memória RAM varia.↩︎