Votaciones nominales en el congreso de Colombia

##Creando la base de datos

library(tidyverse)
## Warning: package 'tidyverse' was built under R version 4.2.3
## Warning: package 'tibble' was built under R version 4.2.3
## Warning: package 'tidyr' was built under R version 4.2.3
## Warning: package 'dplyr' was built under R version 4.2.3
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.1.4     ✔ readr     2.1.4
## ✔ forcats   1.0.0     ✔ stringr   1.5.0
## ✔ ggplot2   3.4.1     ✔ tibble    3.2.1
## ✔ lubridate 1.9.2     ✔ tidyr     1.3.1
## ✔ purrr     1.0.1     
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag()    masks stats::lag()
## ℹ Use the ]8;;http://conflicted.r-lib.org/conflicted package]8;; to force all conflicts to become errors
library(readxl)
## Warning: package 'readxl' was built under R version 4.2.3
library(dplyr)
library(writexl)

Camara22 <- read_excel("COL Legislators Code.xlsx")
## New names:
## • `leg_id` -> `leg_id...3`
## • `` -> `...5`
## • `leg_id` -> `leg_id...7`
Congreso0618 <- read_excel("COL Legislative Comp 2006 2018.xlsx")

Join de los representantes a la cámara (06-18) que tengan código de departamento y hayan repetido su curul.

Camara22_join <- left_join(Camara22, Congreso0618, by = join_by(fst == name, 
                                               lst ==last_name_1, 
                                               ...5 == last_name_2), 
          )

Exportar la base de datos para limpiarla en excel.

write_excel_csv2(Camara22_join, "COL Legislators Code 1.xlsx")

Congreso 2018-2022

Ahora importamos los datos de las elecciones legislativas de 2018 desde el CEDAE y la Registraduría (https://cedae.datasketch.co/datos-democracia/resultados-electorales/descarga-los-datos/). También incluimos el directorio de movimentos políticos para tener los nombres dentro de las bases de datos.

Senado18 <- read_csv("2018_senado.dta.csv")
## Rows: 318620 Columns: 16
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (8): tipo_eleccion, fecha_eleccion, departamento, municipio, circunscrip...
## dbl (8): id_electoral, ano, coddpto, codmpio, codigo_partido, codigo_lista, ...
## 
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Camara18 <- read_csv("2018_camara.dta.csv")
## Rows: 110125 Columns: 16
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (8): tipo_eleccion, fecha_eleccion, departamento, municipio, circunscrip...
## dbl (8): id_electoral, ano, coddpto, codmpio, codigo_partido, codigo_lista, ...
## 
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Cod_partidos <- read_xlsx("~/Uniandes/Oposición/Partidos_Electorales.xlsx")

Ahora filtramos para solo tener la base de datos de candidatos que obtuvieron su curul.

# Candidatos con curul, se agrupa por candidato y partido único y se calcula el total de votos por candidato en listas abiertas. Se colapsa la base de datos para que quede una observación por candidato. 

Senado18 <- Senado18 %>%
  subset(curules == 1) %>%
  group_by(codigo_lista, codigo_partido) %>%
  mutate(total_votos = sum(votos)) %>%
  distinct(ano, tipo_eleccion, primer_apellido, segundo_apellido, nombres, total_votos, curules)


# Candidatos con curul, agrupa por candidato y calcula votos. Luego se cambia la variable de departamentos para candidatos de circunscripciones especiales, se colapsa la base de datos y se corta para que quede un candidato por observación. 

Camara18 <- Camara18 %>%
  subset(curules == 1) %>%
  group_by(codigo_lista, codigo_partido, primer_apellido, nombres) %>%
  mutate(total_votos = sum(votos)) %>%
  ungroup() %>%
  mutate(coddpto = as.character(coddpto),
         coddpto =
           case_when(circunscripcion == "Afrodescendientes" ~ "Afro",
                     circunscripcion == "Indígena" ~ "Ind",
                     circunscripcion == "Especial Internacional" ~ "Exterior", 
                     TRUE ~ coddpto), 
         departamento = 
           case_when(circunscripcion == "Afrodescendientes" ~ "AFRODESCENDIENTES",
                     circunscripcion == "Indígena" ~ "INDIGENA",
                     circunscripcion == "Especial Internacional" ~ "EXTERIOR", 
                     TRUE ~ departamento)) %>%
  distinct(codigo_lista, codigo_partido, ano, tipo_eleccion, coddpto, departamento, circunscripcion, primer_apellido, segundo_apellido, nombres, total_votos, curules)%>%
   group_by(nombres, primer_apellido, segundo_apellido) %>%
   slice(1)

Ahora hacemos la unión para incluir el nombre del movimiento político por el cual se escogió a cada congresista. Y unimos ambas bases de datos.

Camara18 <- left_join(Camara18, Cod_partidos, 
                      by = join_by("codigo_partido" == "codigo_partido"))

Senado18 <- left_join(Senado18, Cod_partidos, 
                      by = join_by("codigo_partido" == "codigo_partido"))

Finalmente, exportamos el archivo para modificarlo en excel y complementar el directorio de congresistas.

write.csv2(Camara18, "COL Legislators Code Camara 2018.csv")

write.csv2(Senado18, "COL Legislators Code Senado 2018.csv")

Codigos 18-26

En una nueva base de datos están los congresistas de 2018-22 y de 2022-26. Debemos asignarle un código de identificación a aquellos que repiten su curul.

Congreso18_26 <- read_excel("Congreso18-26.xlsx")

Para esto creamos nuevas bases para 2018 y 2022 en donde se filtran los candidatos de cada cuatrenio y se eliminan las columnas del código de identiificación para evitar repetir observaciones. Luego, se crean las bases de ID para cada congreso basado en los códigos originales que tienen de 2006 a 2018.

# Nueva base de datos con 2018 sin leg_id. Se elimina party_real pues no estaba en la base original. 

Congreso18 <- Congreso18_26 %>%
  subset(term=="2018-2022") %>%
  mutate(party_real = NULL,
         leg_id = NULL)

# Igual para el congreso 2022, sin eliminar leg_id pues son datos útiles para quienes repiten el código o para identificar variaciones. 

Congreso22 <- Congreso18_26 %>%
  subset(term=="2022-2026") %>%
  mutate(party_real = NULL)

# Se arman los códigos para 2022 de tal manera que si tienen un código previo, se deje, pero si ya estaban en la base anterior, se les asigna el código que tenían en 2006-18.

ID_Congreso22 <- Congreso0618 %>% 
  distinct(leg_id, name, last_name_1, last_name_2) %>%
  right_join(Congreso22, 
             by = join_by("name" == "name", "last_name_1" == "last_name_1", 
                          "last_name_2" == "last_name_2")) %>%
  mutate(leg_id = ifelse(!is.na(leg_id.x), leg_id.x, leg_id.y), 
         leg_id.x = NULL,
         leg_id.y = NULL)

# Se unen ambas bases de datos para leugo asignar códigos a 2018. 

Congreso0618_2226 <- rbind(Congreso0618, ID_Congreso22)

ID_Congreso18 <- Congreso0618_2226 %>% 
  distinct(leg_id, name, last_name_1, last_name_2) %>%
  right_join(Congreso18, 
             by = join_by("name" == "name", "last_name_1" == "last_name_1", 
                          "last_name_2" == "last_name_2"))

# La base final incluye a todos los códigos de 2006 hasta 2026. 

Congreso1826 <- rbind(ID_Congreso18, ID_Congreso22)

Se exportan las bases de datos para luego modificarlas en excel.

write.csv2(ID_Congreso18, "ID Congreso 2018.csv")

write.csv2(ID_Congreso22, "ID Congreso 2022.csv")

Hay algunos datos faltantes en la base de 2006 a 2018, pues aparecen observaciones que no tienen término o no tienen la cámara legislativa asignada. En algunos casos es por fallos en la base de datos de Congreso Visible, de donde se hizo la base origninal; y en otros casos es porque hay congresistas de legislaturas posteriores que se introdujeron en esta base antigua. Para añadir esta información, filtramos la base para encontrar a los congresistas con datos faltantes y luego se une con la base completa para llenar sus datos. Como se repiten columnas, se debe mutar cada columna para priorizar la información nueva.

Congreso0618_f <- left_join(subset(Congreso0618, is.na(term)), subset(Congreso1826, select = c(leg_id, term, chamber_id, last_name_1, last_name_2, name, dpto_code, party_code, votes, senator, house, replaced, name_replacement, date_replacement, committee, pres_committe, pres_term, vipres_committe, vipres_term)),
                            by = join_by("leg_id" == "leg_id", 
                                         "last_name_1" == "last_name_1", 
                          "last_name_2" == "last_name_2",
                          "name" == "name")) %>%
  mutate(term = ifelse(!is.na(term.x), term.x, term.y), 
         term.x = NULL,
         term.y = NULL,
         chamber_id = ifelse(!is.na(chamber_id.x), chamber_id.x, chamber_id.y), 
         chamber_id.x = NULL,
         chamber_id.y = NULL,
         dpto_code = ifelse(!is.na(dpto_code.x), dpto_code.x, dpto_code.y), 
         dpto_code.x = NULL,
         dpto_code.y = NULL,
         party_code = ifelse(!is.na(party_code.x), party_code.x, party_code.y), 
         party_code.x = NULL,
         party_code.y = NULL,
         votes = ifelse(!is.na(votes.x), votes.x, votes.y), 
         votes.x = NULL,
         votes.y = NULL,
         senator = ifelse(!is.na(senator.x), senator.x, senator.y), 
         senator.x = NULL,
         senator.y = NULL,
         house = ifelse(!is.na(house.x), house.x, house.y), 
         house.x = NULL,
         house.y = NULL,
         replaced = ifelse(!is.na(replaced.x), replaced.x, replaced.y), 
         replaced.x = NULL,
         replaced.y = NULL,
         name_replacement = ifelse(!is.na(name_replacement.x), name_replacement.x, name_replacement.y), 
         name_replacement.x = NULL,
         name_replacement.y = NULL,
         date_replacement = ifelse(!is.na(date_replacement.x), date_replacement.x, date_replacement.y), 
         date_replacement.x = NULL,
         date_replacement.y = NULL,
         committee = ifelse(!is.na(committee.x), committee.x, committee.y), 
         committee.x = NULL,
         committee.y = NULL,
         pres_committe = ifelse(!is.na(pres_committe.x), pres_committe.x, pres_committe.y), 
         pres_committe.x = NULL,
         pres_committe.y = NULL,
         pres_term = ifelse(!is.na(pres_term.x), pres_term.x, pres_term.y), 
         pres_term.x = NULL,
         pres_term.y = NULL,
         vipres_committe = ifelse(!is.na(vipres_committe.x), vipres_committe.x, vipres_committe.y), 
         vipres_committe.x = NULL,
         vipres_committe.y = NULL,
         vipres_term = ifelse(!is.na(vipres_term.x), vipres_term.x, vipres_term.y), 
         vipres_term.x = NULL,
         vipres_term.y = NULL)

Luego se exporta la información de los congresistas faltantes para introducirla manualmente en excel.

write.csv2(Congreso0618_f, "Congresistas faltantes 2006 - 2014.csv")

Hubo un daño en la base de datos original, pues faltan datos de algunas columnas pero hay información nueva que se debe conservar. Importamos la base nueva para añadirle los datos que se perdieron sin eliminar las nuevas columnas u observaciones.

Mala <- read_excel("Base mala 0614.xlsx")

Se hace una unión entre la base mala y la base del congreso 0618 con todas sus columnas. Pero se crean nuevas columnas mediante mutate para conservar la información nueva, si existe, y si no se dejan los datos antiguos.

Congreso0618_B <- left_join(Mala, subset(Congreso0618, select = c(term, chamber_id, leg_id, last_name_1, last_name_2, name, dpto_code, party_code, votes, first_year_cong, first_year_term, terms, senator, house, replaced, name_replacement, date_replacement, committee, pres_committe, pres_term, vipres_committe, vipres_term)),
                            by = join_by("leg_id" == "leg_id", 
                                         "last_name_1" == "last_name_1", 
                          "last_name_2" == "last_name_2",
                          "name" == "name",
                          "term" == "term")) %>%
  mutate(chamber_id = ifelse(!is.na(chamber_id.x), chamber_id.x, chamber_id.y), 
         chamber_id.x = NULL,
         chamber_id.y = NULL,
         dpto_code = ifelse(!is.na(dpto_code.x), dpto_code.x, dpto_code.y), 
         dpto_code.x = NULL,
         dpto_code.y = NULL,
         party_code = ifelse(!is.na(party_code.x), party_code.x, party_code.y), 
         party_code.x = NULL,
         party_code.y = NULL,
         votes = ifelse(!is.na(votes.x), votes.x, votes.y), 
         votes.x = NULL,
         votes.y = NULL,
         first_year_cong = ifelse(!is.na(first_year_cong.x), first_year_cong.x, first_year_cong.y), 
         first_year_cong.x = NULL,
         first_year_cong.y = NULL,
         first_year_term = ifelse(!is.na(first_year_term.x), first_year_term.x, first_year_term.y), 
         first_year_term.x = NULL,
         first_year_term.y = NULL,
         terms = ifelse(!is.na(terms.x), terms.x, terms.y), 
         terms.x = NULL,
         terms.y = NULL,
         senator = ifelse(!is.na(senator.x), senator.x, senator.y), 
         senator.x = NULL,
         senator.y = NULL,
         house = ifelse(!is.na(house.x), house.x, house.y), 
         house.x = NULL,
         house.y = NULL,
         replaced = ifelse(!is.na(replaced.x), replaced.x, replaced.y), 
         replaced.x = NULL,
         replaced.y = NULL,
         name_replacement = ifelse(!is.na(name_replacement.x), name_replacement.x, name_replacement.y), 
         name_replacement.x = NULL,
         name_replacement.y = NULL,
         date_replacement = ifelse(!is.na(date_replacement.x), date_replacement.x, date_replacement.y), 
         date_replacement.x = NULL,
         date_replacement.y = NULL,
         committee = ifelse(!is.na(committee.x), committee.x, committee.y), 
         committee.x = NULL,
         committee.y = NULL,
         pres_committe = ifelse(!is.na(pres_committe.x), pres_committe.x, pres_committe.y), 
         pres_committe.x = NULL,
         pres_committe.y = NULL,
         pres_term = ifelse(!is.na(pres_term.x), pres_term.x, pres_term.y), 
         pres_term.x = NULL,
         pres_term.y = NULL,
         vipres_committe = ifelse(!is.na(vipres_committe.x), vipres_committe.x, vipres_committe.y), 
         vipres_committe.x = NULL,
         vipres_committe.y = NULL,
         vipres_term = ifelse(!is.na(vipres_term.x), vipres_term.x, vipres_term.y), 
         vipres_term.x = NULL,
         vipres_term.y = NULL)

Finalmente se exporta la base para añadirla al resto de los datos en excel.

write.csv2(Congreso0618_B, "Base buena 0614.csv")

Verificación de Datos en Reemplazos y Directorio Legislativo

# Cargar las bibliotecas necesarias
library(readxl)
library(dplyr)

# Cargar los datos desde la ruta proporcionada
reemplazos <- read_excel("C:/Users/tomas/OneDrive/Documents/UniAndes/Votaciones nominales/Directorio de Congresistas 06-26/Reemplazos.xlsx")
directorio_legislativo <- read_excel("C:/Users/tomas/OneDrive/Documents/UniAndes/Votaciones nominales/Directorio de Congresistas 06-26/COL Legislative Directory.xlsx")

Verificación de Nombres Faltantes

El siguiente paso consiste en verificar si existen registros en la hoja de reemplazos que no estén presentes en el directorio legislativo. Para ello, se comparan las columnas de primer apellido (last_name_1) y nombre (name). Cualquier observación en la hoja de reemplazos que no tenga una coincidencia en el directorio legislativo será marcada como faltante.

# Verificar qué registros de la hoja de reemplazos no están en el directorio legislativo
nombres_faltantes <- reemplazos %>%
  filter(!(last_name_1 %in% directorio_legislativo$last_name_1 & name %in% directorio_legislativo$name))

# Mostrar los nombres faltantes
print(nombres_faltantes)
## # A tibble: 0 × 3
## # ℹ 3 variables: last_name_1 <chr>, last_name_2 <chr>, name <chr>

Verificación de Observaciones Duplicadas

Para asegurarse de que no hay duplicados en el directorio legislativo, se verifica si existen observaciones que coincidan en el nombre, primer apellido, segundo apellido y término legislativo (term). Si se encuentran observaciones duplicadas, se listarán.

duplicated: Verifica si hay filas que se repiten en función de las columnas seleccionadas: nombre, apellido 1, apellido 2, y término legislativo. fromLast = TRUE: Asegura que tanto la primera como la última instancia de duplicados sean capturadas. print(duplicados): Imprime las observaciones duplicadas para su revisión.

# Verificar observaciones duplicadas basadas en nombre, apellido 1, apellido 2 y term
duplicados <- directorio_legislativo %>%
  filter(duplicated(select(., name, last_name_1, last_name_2, term)) | 
         duplicated(select(., name, last_name_1, last_name_2, term), fromLast = TRUE))

# Mostrar las filas duplicadas
print(duplicados)
## # A tibble: 7 × 24
##   term      chamber_id leg_id leg_id_b last_name_1 last_name_2 name    dpto_code
##   <chr>     <chr>      <chr>  <chr>    <chr>       <chr>       <chr>   <chr>    
## 1 2014-2018 HOUSE      C0022  <NA>     CASTIBLANCO PARRA       JAIRO … 15       
## 2 2014-2018 HOUSE      C0078  <NA>     CASTIBLANCO PARRA       JAIRO … 15       
## 3 <NA>      <NA>       <NA>   <NA>     <NA>        <NA>        <NA>    <NA>     
## 4 <NA>      <NA>       <NA>   <NA>     <NA>        <NA>        <NA>    <NA>     
## 5 <NA>      <NA>       <NA>   <NA>     <NA>        <NA>        <NA>    <NA>     
## 6 <NA>      <NA>       <NA>   <NA>     <NA>        <NA>        <NA>    <NA>     
## 7 <NA>      <NA>       <NA>   <NA>     <NA>        <NA>        <NA>    <NA>     
## # ℹ 16 more variables: party_code <chr>, party_real <chr>, votes <dbl>,
## #   first_year_cong <dbl>, first_year_term <dbl>, terms <dbl>, senator <dbl>,
## #   house <dbl>, replaced <dbl>, name_replacement <chr>,
## #   date_replacement <chr>, committee <dbl>, pres_committe <dbl>,
## #   pres_term <chr>, vipres_committe <dbl>, vipres_term <chr>

Directorio individual

Se ha generado un directorio legislativo donde cada observación corresponde a una persona única, independientemente del cuatrienio en el que sirvió. Para lograr esto, se seleccionaron las columnas de ID, nombre, primer apellido, y segundo apellido, eliminando las observaciones duplicadas basadas en los apellidos y nombres. El resultado se ha guardado como un archivo de Excel titulado COL Individual Legislative Directory.xlsx.

# Seleccionar solo las columnas 'term', 'name', 'last_name_1', y 'last_name_2'
directorio_individual <- directorio_legislativo %>%
  select(leg_id, name, last_name_1, last_name_2)

# Eliminar duplicados para que solo quede una observación por persona
directorio_individual <- directorio_individual %>%
  distinct(name, last_name_1, last_name_2, .keep_all = TRUE)

# Guardar el nuevo directorio como un archivo Excel
write_xlsx(directorio_individual, "C:/Users/tomas/OneDrive/Documents/UniAndes/Votaciones nominales/Directorio de Congresistas 06-26/COL Individual Legislative Directory.xlsx")

# Comprobar que no haya duplicados por código o por nombres
directorio_individual %>% filter(duplicated(leg_id, fromLast = TRUE))
## # A tibble: 93 × 4
##    leg_id name            last_name_1   last_name_2
##    <chr>  <chr>           <chr>         <chr>      
##  1 <NA>   <NA>            <NA>          <NA>       
##  2 <NA>   RICHARD ALFONSO AGUILAR       VILLA      
##  3 <NA>   ESPERANZA       ANDRADE       DE OSSO    
##  4 <NA>   GUSTAVO         BOLIVAR       MORENO     
##  5 <NA>   ANA MARIA       CASTANEDA     GOMEZ      
##  6 <NA>   JUAN LUIS       CASTRO        CORDOBA    
##  7 <NA>   RUBY HELENA     CHAGUI        SPATH      
##  8 <NA>   ALEJANDRO       CORRALES      ESCOBAR    
##  9 <NA>   LUIS EDUARDO    DIAZ GRANADOS TORRES     
## 10 <NA>   JOSE RITTER     LOPEZ         PENA       
## # ℹ 83 more rows
directorio_individual %>%
  filter(duplicated(select(., name, last_name_1, last_name_2)) | 
         duplicated(select(., name, last_name_1, last_name_2), fromLast = TRUE))
## # A tibble: 0 × 4
## # ℹ 4 variables: leg_id <chr>, name <chr>, last_name_1 <chr>, last_name_2 <chr>