As eleições de 2022 representam um momento crucial para a democracia brasileira, com um foco especial na análise exploratória da eleição para o cargo executivo estadual em São Paulo.
Com uma acirrada disputa política, candidatos de diferentes partidos expuseram suas convicções e posicionamentos na busca pelo voto dos eleitores. Durante o processo eleitoral, debates, propagandas e engajamento do eleitorado foram elementos-chave.
Essa eleição foi marcada como uma das mais polarizadas da história recente, e faremos uma análise dos dados abertos do TSE para extrair informações relevantes.
Assim, com o objetivo de gerar algumas problemáticas no projeto, solicitei ao ChatGPT que me fizesse perguntas sobre os dados da eleição de 2022 para o governo de São Paulo, e foram feitos os seguintes posicionamentos:
1 - Qual foi o número total de eleitores que foram votar em São Paulo nas eleições estaduais para governador de 2022?
2 - Quantos candidatos concorreram ao cargo de governador em São Paulo?
3 - Qual foi a porcentagem de votos válidos recebidos pelo candidato eleito?
4 - Qual foi a porcentagem de abstenção nas eleições estaduais de São Paulo para governador?
5 - Quantos votos nulos e brancos foram registrados em São Paulo na eleição?
6 - Quais foram as principais cidades em São Paulo onde o candidato eleito obteve maior votação?
7 - Qual foi a diferença de votos entre o primeiro e o segundo colocado na eleição para governador em São Paulo?
Bom, primeiramente vamos selecionar as cores para cada um dos candidatos e colocar dentro de um objeto. Além disso, também teremos os pacotes utilizados na análise:
cores <- c('TARCISIO GOMES DE FREITAS' = '#4047ad',
'FERNANDO HADDAD' = '#802d34',
'RODRIGO GARCIA' = '#17330e',
'VOTO BRANCO' = '#242222',
'VOTO NULO' = '#141414',
'OUTROS' = '#333030')
#Pacotes
library("tidyverse")
library("geobr")
library("readxl")
library("abjutils")
library('stringr')
Primeiro baixamos o csv dos dados brutos no site do portal de dados abertos do TSE: dados.
Depois usaremos a função read.csv2 para realizar a leitura dos dados, importante utilizar o argumento fileEncoding devido a acentuação contida no nome dos munícipios e dos candidatos.
E depois realizaremos alguns filtros para selecionar apenas os dados referentes ao primeiro turno e a votação para governador.
## coleta de dados
dados_votacao_sp <- read.csv2("~/Consultas/Outros/eleicao/votacao_secao_2022_SP.csv",
fileEncoding = "latin1")
Agora que estamos com os dados brutos vamos começar a realizar as primeiras tratativas. Assim, primeiro pegaremos apenas os dados referentes ao primeiro turno e apenas para o cargo de governador. O código a seguir filtra os dados da votação com as nossas necessidades e os coloca no objeto data1.
Logo depois, nos objetos votes_x_percent e valid_votes, somamos os votos por candidato e não por municípios para chegarmos as primeiras respostas:
# filtro primeiro turno
data1 <-
dados_votacao_sp %>%
filter(DS_CARGO == 'GOVERNADOR', #filtra o cargo para governador
NR_TURNO == "1") %>% #filtra apenas o primeiro turno
select(NM_VOTAVEL, NM_MUNICIPIO, QT_VOTOS) #seleciona apenas as colunas referentes ao nome, municipio e quantidade de votos
# preparando as tabelas - somando os resultados por candidatos
votes_x_percent <-
data1 %>%
select(NM_VOTAVEL, QT_VOTOS) %>% #seleciona apenas o nome e a quantidade de votos
group_by(NM_VOTAVEL) %>% #cria um grupo por nome de candidato
summarise(sum(QT_VOTOS)) %>% # cria um sumário com a soma dos votos por candidato
rename(votos = "sum(QT_VOTOS)") %>%
rename(candidato = "NM_VOTAVEL") %>%
mutate(percentual = round(votos/sum(votos)*100, 2)) %>% #cria uma outra coluna com o percentual de votos dos candidatos
arrange(desc(votos))
valid_votes <-
data1 %>%
select(NM_VOTAVEL, QT_VOTOS) %>%
group_by(NM_VOTAVEL) %>%
summarise(sum(QT_VOTOS)) %>%
rename(votos = "sum(QT_VOTOS)") %>%
rename(candidato = "NM_VOTAVEL") %>%
filter(candidato != "VOTO NULO" &
candidato != "VOTO BRANCO") %>%
mutate(percentual = round(votos/sum(votos)*100, 2)) %>%
arrange(desc(votos))
## tabela para o grafico
primeiros_candidatos <- head(votes_x_percent, 5)
outros_candidatos <-
votes_x_percent %>%
tail(7) %>%
summarise(candidato = 'OUTROS',
votos = sum(votos),
percentual = sum(percentual))
votos_unificacao1 <-
rbind(primeiros_candidatos, outros_candidatos)
Apenas para melhorar a visualização futura, vamos unificar todos os candidatos que tiveram um montante inferior a 2% dos votos em uma coluna chamada de “outros”.
## Tabela de unificacao dos outros candidatos
primeiros_candidatos <- head(votes_x_percent, 5) #filtra os 5 primeiros registros
outros_candidatos <-
votes_x_percent %>%
tail(7) %>% #filtra os 7 ultimos registros
summarise(candidato = 'OUTROS', #cria o nome Outros
votos = sum(votos), #soma os 7 ultimos registros de votacao
percentual = sum(percentual)) #soma os percentuais dos 7 ultimos
votos_unificacao1 <-
rbind(primeiros_candidatos, outros_candidatos) #unifica os 5 primeiros com os 7 ultimos
Agora faremos as mesmas tratativas para os dados do segundo turno:
## segundo turno criamos o objeto data2 para armazenar
data2 <-
dados_votacao_sp %>%
filter(DS_CARGO == 'GOVERNADOR',
NR_TURNO == "2") %>% #filtro para o numero do turno
select(NM_VOTAVEL, NM_MUNICIPIO, QT_VOTOS)
## Somar por candidato
votes_x_percent2 <-
data2 %>%
select(NM_VOTAVEL, QT_VOTOS) %>%
group_by(NM_VOTAVEL) %>%
summarise(sum(QT_VOTOS)) %>%
rename(votos = "sum(QT_VOTOS)") %>%
rename(candidato = "NM_VOTAVEL") %>%
mutate(percentual = round(votos/sum(votos)*100, 2)) %>%
arrange(desc(votos))
## Somar por candidatos apenas os votos validos
valid_votes2 <-
data2 %>%
select(NM_VOTAVEL, QT_VOTOS) %>%
group_by(NM_VOTAVEL) %>%
summarise(sum(QT_VOTOS)) %>%
rename(votos = "sum(QT_VOTOS)") %>%
rename(candidato = "NM_VOTAVEL") %>%
filter(candidato != "VOTO NULO" &
candidato != "VOTO BRANCO") %>%
mutate(percentual = round(votos/sum(votos)*100, 2)) %>%
arrange(desc(votos))
Faremos uma separação dos votos válidos para uma das respostas futuras, basicamente usaremos o mesmo código anterior só que com os dados válidos:
## Tabela de unificacao dos outros candidatos
primeiros_candidatos2 <- head(valid_votes, 3) #filtra os 3 primeiros registros
outros_candidatos2 <-
valid_votes %>%
filter(candidato != 'VOTO NULO',
candidato != 'VOTO BRANCO') %>% #retira os votos de abstencao
tail(7) %>% #filtra os 7 ultimos registros
summarise(candidato = 'OUTROS', #cria o nome Outros
votos = sum(votos), #soma os 7 ultimos registros de votacao
percentual = sum(percentual)) #soma os percentuais dos 7 ultimos
votos_unificacao2 <-
rbind(primeiros_candidatos2, outros_candidatos2) #unifica os 5 primeiros com os 7 ultimos
Vamos criar uma visualização de dados em colunas, utilizando o ggplot2:
## graficos de comparacao
## grafico de quantidade absoluta de votos por candidato no primeiro turno
g1 <-
votos_unificacao1 %>%
ggplot()+
aes(x = reorder(candidato, -votos), y = votos, fill = candidato)+ #seleciona os eixos do grafico
geom_bar(stat = 'identity')+
geom_text(aes(label=votos, #cria os labels nas barras
vjust=1.5),
color='white',
fontface='bold')+
scale_fill_manual(values = cores)+ #seleciona as cores das barras
labs(x='',
y='',
title='Quantidade de votos por candidato (Primeiro Turno)')+
theme_bw()+
theme(axis.text.y = element_blank(),
legend.position = 'none',
plot.title = element_text(face='bold',
size=11),
axis.text.x = element_text(face = 'bold',
size = 8,
color='black'))
## grafico de quantidade percentual de votos por candidato no primeiro turno
g2 <- votos_unificacao1 %>%
ggplot()+
aes(x = reorder(candidato, -percentual), y = percentual, fill= candidato)+
geom_bar(stat = 'identity')+
geom_text(aes(label=percentual,
vjust=1.5),
color='white',
fontface='bold')+
scale_fill_manual(values = cores)+
labs(x='',
y='',
title = 'Percentual de votos por candidato (Primeiro Turno)')+
theme_bw()+
theme(axis.text.y = element_blank(),
legend.position = 'none',
plot.title = element_text(face='bold',
size=11),
axis.text.x = element_text(face = 'bold',
size = 8,
color='black'))
## grafico de quantidade absoluta de votos por candidato no segundo turno
g3 <-
votes_x_percent2 %>%
ggplot()+
aes(x = reorder(candidato, -votos), y = votos, fill = candidato)+
geom_bar(stat = 'identity')+
geom_text(aes(label=votos,
vjust=1.5),
color='white',
fontface='bold')+
scale_fill_manual(values = cores)+
labs(x='',
y='',
title = 'Quantidade de votos por candidato (Segundo Turno)')+
theme_bw()+
theme(axis.text.y = element_blank(),
legend.position = 'none',
plot.title = element_text(face='bold',
size=11),
axis.text.x = element_text(face = 'bold',
size = 8,
color='black'))
## grafico de quantidade percentual de votos por candidato no segundo turno
g4 <-
votes_x_percent2 %>%
ggplot()+
aes(x = reorder(candidato, -percentual), y = percentual, fill = candidato)+
geom_bar(stat = 'identity')+
geom_text(aes(label=percentual,
vjust=1.5),
color='white',
fontface='bold')+
scale_fill_manual(values = cores)+
labs(x='',
y='',
title='Percentual de votos por candidato (Segundo Turno)')+
theme_bw()+
theme(axis.text.y = element_blank(),
legend.position = 'none',
plot.title = element_text(face='bold',
size=11),
axis.text.x = element_text(face = 'bold',
size = 8,
color='black'))
Agora podemos criar a visualização conjunta dos votos absolutos do primeiro turno com a função grid.arrange:
gridExtra::grid.arrange(g1,g3)
E também a visualização conjunta dos votos percentuais por candidato:
gridExtra::grid.arrange(g2,g4)
Agora com todas as manipulações e visualizações feitas, podemos responder as perguntas:
Para isso, basta somar todas as seções de votação de votação do primeiro turno:
print(sum(votes_x_percent$votos))
## [1] 27147847
print(sum(votes_x_percent2$votos)
## [1] 27341816
Assim, o número total de eleitores que foram as urnas no primeiro turno foi de 27147847 e no segundo turno de 27341816.
Nesse caso, apenas devemos somar a quantidade de nomes únicos na coluna de candidatos do primeiro turno, porém usaremos o objeto com votos válidos, que já desconsidera votos brancos e nulos
print(length(unique(valid_votes$candidato)))
## [1] 10
Assim, chegamos a reposta da segunda questão, onde tinhamos 10 candidatos concorrendo para o cargo de governador de São Paulo.
Para isso, podemos utilizar os objetos criados anteriormente para votos válidos e apenas criar a visualização de porcentagem:
g5 <- votos_unificacao2 %>%
ggplot()+
aes(x = reorder(candidato, -percentual), y = percentual, fill= candidato)+
geom_bar(stat = 'identity')+
geom_text(aes(label=percentual,
vjust=1.5),
color='white',
fontface='bold')+
scale_fill_manual(values = cores)+
labs(x='',
y='',
title = 'Percentual de votos validos por candidato (Primeiro Turno)')+
theme_bw()+
theme(axis.text.y = element_blank(),
legend.position = 'none',
plot.title = element_text(face='bold',
size=11),
axis.text.x = element_text(face = 'bold',
size = 8,
color='black'))
g6 <-
valid_votes2 %>%
ggplot()+
aes(x = reorder(candidato, -percentual), y = percentual, fill = candidato)+
geom_bar(stat = 'identity')+
geom_text(aes(label=percentual,
vjust=1.5),
color='white',
fontface='bold')+
scale_fill_manual(values = cores)+
labs(x='',
y='',
title='Percentual de votos validos por candidato (Segundo Turno)')+
theme_bw()+
theme(axis.text.y = element_blank(),
legend.position = 'none',
plot.title = element_text(face='bold',
size=11),
axis.text.x = element_text(face = 'bold',
size = 8,
color='black'))
E plotar a visualização:
gridExtra::grid.arrange(g5,g6)
Assim, podemos ver que no primeiro turno, o candidato eleito Tarcísio Gomes, teve 42.32% dos votos válidos e no segundo turno 55.27% dos votos válidos. Como podemos ver no gráfico.
Segundo os dados do TSE, São Paulo tem 34667793 eleitores aptos, considerando esse número, teríamos:
print(round(abs(((34667793-27147847)/34667793)*100), 2))
## [1] 21.69
print(round(abs(((34667793-27341816)/34667793)*100), 2))
## [1] 21.13
Assim, a porcentagem de abstenção, pessoas que não compareceram as urnas para votação foi de 21.69% no primeiro turno e levemente menor no segundo, 21.13%.
Quando falamos dos eleitores que compareceram mas que votaram nulo ou branco, podemos observar nos gráficos feitos anteriormente para visualização inicial, sendo:
gridExtra::grid.arrange(g1,g3)
No primeiro turno, 2149776 votos nulos e 1645522 brancos. Já no segundo turno 1849298 nulos e 1102504 brancos.
Quando falamos de maior votação, obviamente, os municípios que tem os maiores colégios eleitorais serão aqueles com maior representatividade na votação. Assim, a Região metropolitana de São Paulo mostrará números mais significativos.
Desse modo, vamos criar uma visualização gráfica que compare os municípios em que Tarcisio teve mais votação do que Haddad. Pintaremos esses lugares de azul, e os que ele recebeu menos votos de vermelho. Para criar isso vamos utilizar o pacote geobr:
### grafico de mapas
## puxar estado do geobr
state <- read_municipality(code_muni = 'SP',
year = 2020) %>%
mutate(muni = toupper(name_muni))
## arrumar dados para o mapa 1 turno
tarcisio1 <- #filtra apenas os dados de votacao do tarcisio
data1 %>%
filter(NM_VOTAVEL == "TARCISIO GOMES DE FREITAS") %>%
group_by(NM_MUNICIPIO) %>%
summarise(sum(QT_VOTOS)) %>%
rename(votos = "sum(QT_VOTOS)") %>%
rename(municipio = "NM_MUNICIPIO")
##haddad
haddad1 <- #filtra apenas os dados de votacao do haddad
data1 %>%
filter(NM_VOTAVEL == "FERNANDO HADDAD") %>%
group_by(NM_MUNICIPIO) %>%
summarise(sum(QT_VOTOS)) %>%
rename(votos = "sum(QT_VOTOS)") %>%
rename(municipio = "NM_MUNICIPIO")
#tarcisio, haddad, rodrigo e others
comparation1 <- #junta as duas tabelas
full_join(tarcisio1, haddad1, by="municipio") %>%
rename(TARCISIO = "votos.x",
HADDAD = "votos.y") %>%
mutate(vencedor = ifelse(`TARCISIO` > `HADDAD`, "TARCISIO", "HADDAD")) %>% #cria tabela com o candidato que teve mais votos em cada municipio
arrange(desc(TARCISIO))
### problema encontrado, alguns municipios tem nomes incorretos no pacote do geobr
## descobrir os nomes errados
setdiff(comparation1$municipio, state$muni)
## [1] "SANTA BÁRBARA D OESTE" "ESTRELA D OESTE" "PALMEIRA D OESTE"
## [4] "SÃO LUÍS DO PARAITINGA" "APARECIDA D OESTE" "SANTA CLARA D OESTE"
## [7] "SANTA RITA D OESTE" "SÃO JOÃO DO PAU D ALHO" "GUARANI D OESTE"
## 9 nomes errados
comparation1$municipio <- gsub("SÃO LUÍS DO PARAITINGA", "SÃO LUIZ DO PARAITINGA", comparation1$municipio)
comparation1$municipio <- gsub("SÃO JOÃO DO PAU D ALHO", "SÃO JOÃO DO PAU D'ALHO", comparation1$municipio)
comparation1$municipio <- gsub("SANTA CLARA D OESTE", "SANTA CLARA D'OESTE", comparation1$municipio)
comparation1$municipio <- gsub("GUARANI D OESTE", "GUARANI D'OESTE", comparation1$municipio)
comparation1$municipio <- gsub("SANTA RITA D OESTE", "SANTA RITA D'OESTE",comparation1$municipio)
comparation1$municipio <- gsub("PALMEIRA D OESTE", "PALMEIRA D'OESTE", comparation1$municipio)
comparation1$municipio <- gsub("SANTA BÁRBARA D OESTE", "SANTA BÁRBARA D'OESTE", comparation1$municipio)
comparation1$municipio <- gsub("ESTRELA D OESTE", "ESTRELA D'OESTE", comparation1$municipio)
comparation1$municipio <- gsub("APARECIDA D OESTE", "APARECIDA D'OESTE", comparation1$municipio)
## depois da correcao realizar a juncao
full_maps1 <- #unir tabela de municipios com a tabelas com a votacao
left_join(state, comparation1, by=c('muni' = 'municipio'))
## mapa primeiro turno
m1 <-
ggplot() +
geom_sf(data = full_maps1,
aes(fill = vencedor),
color = "black") +
scale_fill_manual(values = c(`TARCISIO` = "#4047ad",
`HADDAD` = "#802d34"))+
theme_bw()+
labs(title = 'Maior quantidade de votos por município de São Paulo',
subtitle = 'TARCISIO VS HADDAD (1º Turno)')+
theme(axis.text.x = element_blank(),
axis.text.y = element_blank(),
plot.title = element_text(size = 11,
face='bold'),
plot.subtitle = element_text(size=9,
face='italic'))
## arrumar dados para o mapa 2 turno
## tarcisio
tarcisio2 <-
data2 %>%
filter(NM_VOTAVEL == "TARCISIO GOMES DE FREITAS") %>%
group_by(NM_MUNICIPIO) %>%
summarise(sum(QT_VOTOS)) %>%
rename(votos = "sum(QT_VOTOS)") %>%
rename(municipio = "NM_MUNICIPIO")
##tarcisio e haddad
haddad2 <-
data2 %>%
filter(NM_VOTAVEL == "FERNANDO HADDAD") %>%
group_by(NM_MUNICIPIO) %>%
summarise(sum(QT_VOTOS)) %>%
rename(votos = "sum(QT_VOTOS)") %>%
rename(municipio = "NM_MUNICIPIO")
comparation2 <-
full_join(tarcisio2, haddad2, by="municipio") %>%
rename(TARCISIO = "votos.x",
HADDAD = "votos.y") %>%
arrange(desc(TARCISIO)) %>%
mutate(vencedor = ifelse(`TARCISIO` > `HADDAD`, "TARCISIO", "HADDAD"))
### problema encontrado, alguns municipios tem nomes incorretos no pacote do geobr
## descobrir os nomes errados
setdiff(comparation2$municipio, state$muni)
## [1] "SANTA BÁRBARA D OESTE" "SÃO LUÍS DO PARAITINGA" "ESTRELA D OESTE"
## [4] "PALMEIRA D OESTE" "APARECIDA D OESTE" "SANTA RITA D OESTE"
## [7] "SANTA CLARA D OESTE" "SÃO JOÃO DO PAU D ALHO" "GUARANI D OESTE"
## 9 nomes errados
comparation2$municipio <- gsub("SÃO LUÍS DO PARAITINGA", "SÃO LUIZ DO PARAITINGA", comparation2$municipio)
comparation2$municipio <- gsub("SÃO JOÃO DO PAU D ALHO", "SÃO JOÃO DO PAU D'ALHO", comparation2$municipio)
comparation2$municipio <- gsub("SANTA CLARA D OESTE", "SANTA CLARA D'OESTE", comparation2$municipio)
comparation2$municipio <- gsub("GUARANI D OESTE", "GUARANI D'OESTE", comparation2$municipio)
comparation2$municipio <- gsub("SANTA RITA D OESTE", "SANTA RITA D'OESTE",comparation2$municipio)
comparation2$municipio <- gsub("PALMEIRA D OESTE", "PALMEIRA D'OESTE", comparation2$municipio)
comparation2$municipio <- gsub("SANTA BÁRBARA D OESTE", "SANTA BÁRBARA D'OESTE", comparation2$municipio)
comparation2$municipio <- gsub("ESTRELA D OESTE", "ESTRELA D'OESTE", comparation2$municipio)
comparation2$municipio <- gsub("APARECIDA D OESTE", "APARECIDA D'OESTE", comparation2$municipio)
## depois da correcao realizar a juncao
full_maps2 <-
left_join(state, comparation2, by=c('muni' = 'municipio'))
## grafico de visualizacao
m2 <-
ggplot() +
geom_sf(data = full_maps2,
aes(fill = vencedor),
color = "black") +
scale_fill_manual(values = c(`TARCISIO` = "#4047ad",
`HADDAD` = "#802d34"))+
theme_bw()+
labs(title = 'Maior quantidade de votos por município de São Paulo',
subtitle = 'TARCISIO VS HADDAD (2º Turno)')+
theme(axis.text.x = element_blank(),
axis.text.y = element_blank(),
plot.title = element_text(size = 11,
face='bold'),
plot.subtitle = element_text(size=9,
face='italic'))
Com os gráficos criados, vamos apenas criar a contagem de municipios por candidatos e visualizar os dois:
print(sum(str_count(full_maps1$vencedor, 'TARCISIO')))
## [1] 539
print(sum(str_count(full_maps2$vencedor, 'TARCISIO')))
## [1] 566
print(sum(str_count(full_maps1$vencedor, 'HADDAD')))
## [1] 106
print(sum(str_count(full_maps2$vencedor, 'HADDAD')))
## [1] 79
gridExtra::grid.arrange(m1, m2)
Assim, no primeiro turno Tarcisio foi vitorioso em 539 municípios, enquanto Haddad foi para 106. Já no segundo turno, o número de Tarcisio sobe para 566, já Haddad os municípios em que Haddad foi o vencedor diminuíram para 79. Que mostra a maior migração dos eleitores de Rodrigo Garcia e dos outros candidatos foram para Tarcisio.
Curiosamente, Tarcisio teve menos votos na maioria dos municípios correspondentes às proximidades da capital, Fernando Haddad vendeu em quase todos, durante o primeiro turno. Além desses locais, Tarcisio apenas teve desvantagem na totalidade de votos, em alguns municípios de Presidente Prudente, Sorocaba, Araraquara e Taubaté. Vencendo em todos os outros.
Como vimos nos gráficos, Tarcisio recebeu 9881995 votos e Haddad 8337139. Já no segundo turno Tarcisio teve 13480643 e Haddad 10909371.
print(round(((9881995-8337139)/9881995)*100, 2))
## [1] 15.63
print(round(((13480643-10909371)/13480643)*100, 2))
## [1] 19.07
No primeiro turno, a diferença foi de 15.63% que passou para 19.07% no segundo turno.
O objetivo dessa análise foi meramente exploratório, tentando usar técnicas de ETL para responder as perguntas feitas pelo ChatGPT, as visualizações também, visaram apenas de maneiras simples dar uma visualização diferente das que encontramos como opção no site do TSE.