- ter 28 maio 2019
- datasets
- Álvaro Justen
- #sql, #command-line, #python
Diversos partidos brasileiros mudaram de nome em 2018, mas você sabe quais são? Motivado por uma dúvida no Twitter resolvi utilizar o dataset eleicoes-brasil para listar as mudanças de nome que aconteceram desde 1996. Vamos utilizar a interface de linha de comando da rows, um pouco de SQL e Python para essa tarefa!
Instalando as dependências¶
Antes de iniciar, criarei um ambiente virtual (virtualenv) utilizando a versão 3.7 do Python (vou utilizar o pyenv e pyenv-virtualenv para isso, mas fique à vontade para utilizar outras ferramentas em seu ambiente). Depois de criado o virtualenv, precisamos instalar a interface de linha de comando da rows:
pyenv virtualenv 3.7.3 eleicoes
pyenv activate eleicoes
pip install rows[cli]
pip install -U https://github.com/turicas/rows/archive/develop.zip#egg=rows
Nota: estamos utilizando a versão em desenvolvimento da rows por conta da correção de alguns bugs. Essa versão (0.4.2) será lançada em breve.
Baixando os dados¶
Para determinar todos os partidos e as mudanças de nome utilizaremos os dados das candidaturas, que contém a sigla e número do partido para cada candidato. Aqui, usei o wget
para baixar o arquivo completo, disponível no Brasil.IO:
wget https://data.brasil.io/dataset/eleicoes-brasil/candidatura.csv.gz
Nota: os dados de candidatura não estão atualizados para visualização na interface do Brasil.IO (ainda sem as informações das eleições de 2018), porém o arquivo acima está atualizado.
Importando no SQLite¶
Como são mais de 2 milhões de candidaturas (veja a quantidade de linhas do arquivo CSV compactado: zcat candidatura.csv.gz | wc -l
), vou transformar o CSV em uma tabela numa base SQLite e utilizar SQL para fazer as consultas mais fácil e rapidamente - a versão 0.4 da rows possui um comando na sua CLI que facilita o processo:
rows csv2sqlite candidatura.csv.gz eleicoes.sqlite
Relaxe por alguns minutos enquanto o arquivo é convertido. :) Enquanto você toma um café, o comando acima irá:
- Descompactar em tempo de execução o arquivo
- Identificar o dialeto do CSV
- Identificar o tipo de cada coluna, inspecionando os primeiros registros
- Criar o banco de dados e a tabela
candidatura
, utilizando os tipos identificados - Adicionar os dados do CSV na tabela
Criando e executando a consulta¶
Cada candidatura possui informações do partido nas colunas numero_partido
e nome_partido
. Vamos criar um arquivo SQL com uma consulta que agrupa as candidaturas por ano da eleição, número e nome do partido, assim teremos todos os partidos que disputaram as eleições, junto com os anos em que isso aconteceu. Crie o arquivo consulta-partidos.sql
com o seguinte conteúdo:
SELECT
ano_eleicao AS ano,
numero_partido AS numero,
nome_partido AS nome
FROM candidatura
WHERE
sigla_partido NOT IN ('PRESTCONTAS', 'NAO', 'SIM')
GROUP BY
ano_eleicao,
numero_partido,
nome_partido
Na consulta eliminamos algumas siglas de partidos que não são interessantes agora (elas aparecem em outros casos, como plebiscitos, e não representam um partido).
Então, voltamos a utilizar CLI da rows para executar a consulta e salvar o resultado num CSV:
rows query "$(cat consulta-partidos.sql)" eleicoes.sqlite --output=partidos-por-ano.csv
Pronto! Com isso teremos um registro por partido por ano. Agora precisamos agrupar por número do partido e entender quais possuem nomes diferentes ao longo dos anos.
Agrupando por Número do Partido¶
Vamos agrupar os dados em partidos-por-ano.csv
utilizando outra consulta SQL. Crie o arquivo partidos-por-numero.sql
com o seguinte conteúdo:
SELECT
numero,
nome,
GROUP_CONCAT(ano) AS anos
FROM table1
GROUP BY
numero,
nome
ORDER BY
numero,
ano
Agora basta executarmos essa consulta no arquivo partidos-por-ano.csv
que geramos anteriormente:
rows query "$(cat partidos-por-numero.sql)" partidos-por-ano.csv --output=partidos-por-numero.csv
Sim, com a rows é possível executar consultas SQL diretamente em arquivos nos formatos suportados pela biblioteca, como CSV, porém utilize essa funcionalidade apenas em arquivos pequenos, pois a conversão pode demorar; para arquivos maiores prefira converter para SQLite com o comando
rows csv2sqlite
(como feito comcandidatura.csv.gz
) e após isso utilizerows query CONSULTA arquivo.sqlite
.
Vamos ao resultado? Podemos visualizar a tabela diretamente no Jupyter Notebook:
import rows
rows.import_from_csv("partidos-por-numero.csv")
Inspecionando os dados podemos ver que 3 nomes de partidos utilizaram o número 11
: PARTIDO PROGRESSISTA BRASILEIRO
, PARTIDO PROGRESSISTA
e PROGRESSISTAS
. Como os anos são contíguos (o primeiro utiliza até 2002, o segundo começa a partir de 2004 e assim por diante), podemos considerar que esse é o mesmo partido que mudou de nome. Isso não acontece com todos os números, como o número 30
, que foi utilizado por PARTIDO GERAL DOS TRABALHADORES
até 2002 e a partir de 2016 pelo PARTIDO NOVO
.
Melhorando a Visualização do Resultado¶
Para finalizar, vamos criar um script Python que agrupa o CSV gerado acima por número de partido e, a partir de cada grupo, verifica os anos em que cada partido aparece para determinar se o partido mudou de nome ou se foi o caso de um partido mais recente reutilizar o número de um partido que não existe mais. Como resultado, o script irá exibir na tela apenas os partidos que mudaram de nome, ou seja, os números de partido que tiveram nomes diferentes em anos de eleição contíguos:
from itertools import groupby
import rows
# Importamos os dados:
partidos_por_numero = rows.import_from_csv("partidos-por-numero.csv")
# Agrupamos por número:
agrupamento = groupby(partidos_por_numero, key=lambda partido: partido.numero)
resultado = []
for numero, partidos in agrupamento:
partidos = list(partidos)
# Se esse número só possui 1 partido, significa que ele não mudou de nome
if len(partidos) == 1:
continue
# Verificarmos os partidos, par a par, para identificar os que participaram
# de eleições contíguas - esses, adicionamos em uma lista, que será impressa
# no final
for partido_1, partido_2 in zip(partidos[:-1], partidos[1:]):
ano_final_partido_1 = int(max(partido_1.anos.split(",")))
ano_inicial_partido_2 = int(min(partido_2.anos.split(",")))
if abs(ano_inicial_partido_2 - ano_final_partido_1) <= 2:
# Eleições contíguas, então é o mesmo partido que mudou de nome!
# Agora vamos só ajustar o período em que a mudança aconteceu:
if ano_final_partido_1 == ano_inicial_partido_2:
datas = [ano_final_partido_1]
periodo = f"em {ano_final_partido_1}"
else:
datas = sorted([ano_final_partido_1, ano_inicial_partido_2])
periodo = f"entre {datas[0]} e {datas[1]}"
texto = f"{partido_1.nome} ({numero}) mudou de nome para {partido_2.nome} {periodo}"
resultado.append((datas, texto))
# Agora vamos ordenar o resultado por data para imprimí-lo na ordem cronológica das alterações:
for datas, texto in sorted(resultado):
print(texto)
Conclusão¶
O fato de existirem dados disponíveis sobre os mais diversos temas nos permite responder a perguntas como essa de maneira imediata, sem a necessidade da criação um pedido de acesso à informação - por esse e outros motivos a transparência ativa é muito importante. Porém, não conseguiríamos responder a essa pergunta em poucos minutos se os dados não estivessem disponíveis em um formato mais acessível e consolidado no Brasil.IO: para gerar esse dataset foram necessárias diversas horas de trabalho criando um programa que baixa, converte, limpa e consolida os dados do Tribunal Superior Eleitoral.
Se você acha o trabalho que desenvolvemos importante, considere fazer uma doação ou colaborar de outras formas. ;)