1 Objetivos

En este tutorial, nos proponemos:

  1. Leer y manejar en R la base de datos de los cómputos distritales de la elección de diputados del 2024, proporcionada por el Instituto Nacional Electoral (INE).

  2. Trabajar con la base de datos de los convenios de coalición acordados para esta elección.

  3. Analizar y determinar la composición de la Cámara de Diputados considerando:

    • El marco legal vigente para la elección de 2024.
    • Los cómputos distritales, descargados directamente de la página oficial del INE.
    • Los convenios de coalición, explicados en este tutorial.

Por composición, entendemos el número de diputados que cada partido obtiene al finalizar el proceso electoral, un aspecto clave ya que las decisiones en la Cámara dependen de las mayorías alcanzadas.

Finalmente, realizaremos análisis básicos y generaremos resultados que serán de interés para investigadores, analistas y cualquier persona interesada en comprender cómo se determina la composición legislativa a partir de los datos electorales.

1.1 Nota Importante

Este tutorial tiene un enfoque exclusivamente académico, diseñado para comprender el proceso mediante el cual se determina la composición de la Cámara de Diputados y para aprender a manejar las bases de datos del INE. Aunque hemos seguido la normativa legal y los datos disponibles con la mayor precisión posible, es importante señalar lo siguiente:

  1. La interpretación de ciertos aspectos de la ley electoral puede variar, lo que podría generar diferencias respecto a los resultados oficiales publicados por el INE.
  2. Los cómputos distritales, aunque representan los resultados oficiales iniciales, pueden haber sido modificados por decisiones del Tribunal Electoral del Poder Judicial de la Federación (TEPJF), como anulaciones de casillas o ajustes derivados de impugnaciones.
  3. Debido a lo anterior, el procedimiento aquí presentado podría producir variaciones en comparación con la conformación oficial de la Cámara de Diputados para la elección de 2024.

Este tutorial tiene como único propósito entender los principios que rigen el cálculo de la composición legislativa y fomentar el análisis crítico de las bases de datos electorales. Los resultados obtenidos no deben considerarse como representativos de los datos oficiales ni como una postura sobre los resultados de esta elección en particular.

2 Cómputdos distritales

México está dividido en 300 distritos electorales federales (artículo 53 de la (CPEUM 2023)), que son las áreas geográficas utilizadas para elegir a los diputados que integran la Cámara de Diputados. Cada distrito agrupa a un cierto número de ciudadanos y es la base para organizar y contar los votos durante las elecciones.

Cuando se realiza una elección, el Instituto Nacional Electoral (INE) utiliza los distritos electorales para llevar a cabo los cómputos distritales, un proceso oficial donde se suman y verifican los votos registrados en las casillas instaladas dentro de cada distrito. Durante este procedimiento, se revisan las actas de votación de cada casilla y, si hay errores o inconsistencias, se pueden realizar recuentos. Al finalizar, los cómputos distritales producen los resultados oficiales que determinan a los ganadores.

No obstante, estos resultados, aunque oficiales, no son inamovibles. El Tribunal Electoral del Poder Judicial de la Federación (TEPJF) tiene la facultad de anular casillas o realizar recuentos en casillas específicas si se detectan irregularidades graves que afecten la certeza de los resultados.

Para garantizar la transparencia, el INE publica una base de datos detallada a nivel de casilla, lo que significa que cada fila en la base corresponde a una casilla electoral específica. Esta base incluye información como el número total de votos por partido o candidato, los votos nulos, y la participación ciudadana registrada en cada casilla. Al analizar esta base de datos, se pueden identificar patrones de votación, evaluar la participación en distintas áreas y explorar cómo se desarrolló el proceso electoral en cada distrito del país.

Los cómputos distritales son fundamentales en el sistema electoral de México y su aplicación depende del tipo de elección.

En las elecciones federales (presidencial, diputados y senadores), se utilizan los 300 distritos federales para consolidar y verificar los votos de todas las casillas dentro de cada distrito. Por ejemplo, cada distrito elige a un diputado federal por el principio de mayoría relativa, y los resultados se determinan mediante los cómputos distritales.

En las elecciones locales (como para gobernadores, congresos locales o alcaldías), se utilizan los distritos locales, que son definidos por cada estado y no siempre coinciden con los distritos federales. En estos casos, los cómputos se realizan a nivel local, de acuerdo con la división territorial electoral correspondiente.

En este tutorial, nos enfocaremos en analizar los cómputos distritales para la elección federal de diputados de 2024, utilizando la base de datos publicada por el INE a nivel de casilla.

2.1 Descargando los datos: Elección Federal de Diputados 2024

Para obtener la base de datos de los cómputos distritales, visita la página oficial del INE:

https://computos2024.ine.mx/

Maximiza la ventana y haz clic en la pestaña superior “Base de Datos”. Luego, selecciona el botón “Descargar” que aparece en la parte izquierda de la página para guardar el archivo comprimido 20240608_2030_COMPUTOS.zip en tu computadora.

Al descomprimir este archivo, encontrarás tres archivos comprimidos adicionales. El que nos interesa para esta tarea es 20240608_2030_COMPUTOS_DIP_FED.zip. Descomprímelo y obtendrás el archivo con los datos de la votación para la elección federal de diputados a nivel casilla: DIP_FED_2024.csv.

Antes de empezar a analizar los datos, es recomendable revisar el archivo LEEME.txt, donde se describe en detalle el contenido de los archivos, los nombres de las variables y sus posibles valores.

El siguiente código carga la base de datos DIP_FED_2024.csv asumiendo que colocamos esta base de datos en el folder BD. Para ello, se utiliza la función fread() de data.table, que es muy eficiente para manejar archivos grandes.

# DIRECTORIO DE TRABAJO
my_dir <- "/Users/carloserwin/Library/CloudStorage/GoogleDrive-carloserwin@sigma.iimas.unam.mx/Mi unidad/IIMAS/PRESENTACIONES/MAS_ALLA_DE_LOS_VOTOS_2024/EXTRAS/"
# LIBRERÍAS NECESARIAS
library(data.table)
library(xtable)
BD0 <- data.frame(fread(paste0(my_dir, "BD/DIP_FED_2024.csv"), skip = 6, na.strings = "-"))
names(BD0)
##  [1] "CLAVE_CASILLA"               "CLAVE_ACTA"                 
##  [3] "ID_ENTIDAD"                  "ENTIDAD"                    
##  [5] "ID_DISTRITO_FEDERAL"         "DISTRITO_FEDERAL"           
##  [7] "SECCION"                     "ID_CASILLA"                 
##  [9] "TIPO_CASILLA"                "EXT_CONTIGUA"               
## [11] "CASILLA"                     "TIPO_ACTA"                  
## [13] "PAN"                         "PRI"                        
## [15] "PRD"                         "PVEM"                       
## [17] "PT"                          "MC"                         
## [19] "MORENA"                      "CANDIDATO.A.INDEPENDIENTE"  
## [21] "PAN_PRI_PRD"                 "PAN_PRI"                    
## [23] "PAN_PRD"                     "PRI_PRD"                    
## [25] "PVEM_PT_MORENA"              "PVEM_PT"                    
## [27] "PVEM_MORENA"                 "PT_MORENA"                  
## [29] "CANDIDATO.A.NO.REGISTRADO.A" "VOTOS.NULOS"                
## [31] "TOTAL_VOTOS_CALCULADOS"      "LISTA_NOMINAL"              
## [33] "OBSERVACIONES"               "MECANISMOS_TRASLADO"        
## [35] "FECHA_HORA"

En este caso, se omiten las primeras 6 filas del archivo mediante el argumento skip = 6, ya que el INE suele incluir comentarios al inicio de las bases de datos, y los datos relevantes comienzan a partir de la fila 6. Además, se indica que los valores “-” deben ser tratados como datos faltantes (NA) con el argumento na.strings = “-”. Finalmente, el resultado se convierte en un data.frame para facilitar su manipulación y se guarda en el objeto BD0.

A continuación, realizamos varios ajustes en los datos para mejorar su manejo y garantizar consistencia.

names(BD0)[c(20, 29, 30, 31)] <- c("CI", "CNR", "NULOS", "TOTAL") 
BD0$ID_ENTIDAD <- gsub('^=\\"|\\\"$', '', BD0$ID_ENTIDAD)
BD0$ID_DISTRITO_FEDERAL <- gsub('^=\\"|\\\"$', '', BD0$ID_DISTRITO_FEDERAL)
BD0$ID_DF <- paste0(BD0$ID_ENTIDAD, BD0$ID_DISTRITO_FEDERAL)

Los pasos incluyen:

  1. Cambiar nombres originales por versiones más manejables: Modificamos los nombres de las variables originales para que sean más cortos, descriptivos y fáciles de trabajar en R.

  2. Corregir detalles en los identificadores de estado y distrito: Los identificadores de estado vienen en el formato “="01"”, mientras que los de distrito federal tienen el formato “="001"”. Esto probablemente se debe a que el INE usa este formato para evitar que programas como Excel interpreten los valores como números en lugar de caracteres. Eliminamos los caracteres adicionales (= y comillas dobles) para obtener valores consistentes y tratarlos como cadenas de texto (e.g., “01” para el estado y “001” para el distrito).

  3. Crear un identificador único de distrito federal: Para identificar de manera única cada distrito federal electoral (de los 300), combinamos las variables de estado y distrito en una nueva columna, asegurando que cada registro sea inequívoco. Esto es necesario porque cada estado tiene su propio distrito federal 1, distrito federal 2, y así sucesivamente.

Con estos ajustes, los datos estarán listos para un análisis sin ambigüedades.

2.1.1 Votos agregados a nivel distrito federal

Finalmente, generamos una nueva base de datos que contiene únicamente las variables necesarias para el análisis. Además, calculamos los sub-totales de votos por distrito federal para cada variable, ignorando las celdas con valores faltantes al realizar las sumas.

BD <- data.table(BD0[, c(36, 13:32)])
BD_DIST <- data.frame(BD[, lapply(.SD, sum, na.rm = TRUE), by = ID_DF])
dim(BD_DIST)
## [1] 300  21
head(BD_DIST)
##   ID_DF    PAN   PRI  PRD  PVEM    PT    MC MORENA CI PAN_PRI_PRD PAN_PRI
## 1 01001  74830 23971 6565  8769  7587 15288  71065  0        2397    1128
## 2 01002  72198  8873 4829  5787  3624 20862  63580  0        2802    1099
## 3 01003 120511 14465 3473  6466  3483 16793  62028  0           0       0
## 4 02001  48257  8753 1451  6802  3726 15030  77248  0        1756     530
## 5 02002  33786  7401 1434  8147  5581 14428  85145  0        1214     393
## 6 02003  23621  9988 2952 11088 10034 13802  84747  0        1117     339
##   PAN_PRD PRI_PRD PVEM_PT_MORENA PVEM_PT PVEM_MORENA PT_MORENA CNR NULOS  TOTAL
## 1     187      56           1853     245         588       482 137  7178 222326
## 2     231      31           3100     198         724       603 218  4533 193292
## 3       0       0           3026     224         727       529 230  9149 241104
## 4      42      19              0       0           0         0 153  7249 171016
## 5      37      21              0       0           0         0 149  8575 166311
## 6      44      32              0       0           0         0 353 10939 169056
##   LISTA_NOMINAL
## 1        364676
## 2        347196
## 3        385495
## 4        331719
## 5        342529
## 6        334438

2.2 Coaliciones

La clave para entender la composición de la Cámara de Diputados después de la elección federal de 2024 es analizar los convenios de coalición. Según el artículo 87 de la (LGPP 2023), los partidos políticos tienen la posibilidad de formar coaliciones para competir en un distrito determinado.

Un aspecto crucial es que, si una coalición gana la diputación en un distrito, el cargo no necesariamente queda en manos del partido que obtuvo más votos dentro de la coalición. Esto se define con antelación en los convenios de coalición, los cuales son negociados y registrados varios meses antes de la elección.

Los convenios de coalición para diputados se pueden descargar en el siguiente enlace:

https://portal.ine.mx/actores-politicos/convenios-de-coalicion/

Para la elección de diputados del 2024, las coaliciones fueron:

  • Fuerza y Corazón por México (FCPM): Formada por los partidos PRI, PAN, y PRD. Los detalles de este convenio se encuentran en las páginas 45 a 55 del documento en PDF.
  • Seguiremos Haciendo Historia (SHH): Integrada por los partidos PT, PVEM, y MORENA. Este convenio está descrito en las páginas 43 a 51 del PDF.
Transformar los convenios de coalición en una base de datos manejable y analizarlos es un paso clave para entender cómo se asignaron las diputaciones en cada distrito electoral. Para facilitar este análisis, ya he realizado la conversión a formato CSV. Puedes descargar la base de datos desde el siguiente enlace:

Descargar Base de Datos

Igual que antes, asumiendo que colocamos esta base de datos en el folder BD, en R se carga de la siguiente manera:

# LEEMOS LAS COALICIONES, SIN EL NOMBRE DEL ESTADO
COAL_D <- as.data.frame(fread(paste0(my_dir, "BD/COAL_D.csv")))[,-2]
dim(COAL_D)
## [1] 300   9
head(COAL_D)
##   ID_ESTADO ID_DISTRITO PAN PRI PRD MORENA PT PVEM CI
## 1         1           1   0   1   0      0  0    1  0
## 2         1           2   1   0   0      1  0    0  0
## 3         1           3   0   0   0      1  0    0  0
## 4         2           1   1   0   0      0  0    0  0
## 5         2           2   1   0   0      0  0    0  0
## 6         2           3   0   0   1      0  0    0  0

Como ya hemos visto anteriormente, para identificar de forma única los distritos federales electorales en las bases de datos, se utilizan las dos variables: ID_ESTADO y ID_DISTRITO.

Las siguientes tres variables, PAN, PRI, y PRD, indican si en un distrito específico se acordó la coalición FCPM. Si alguna de estas variables tiene un valor de 1, significa que, en caso de que la coalición gane la diputación en ese distrito, el partido correspondiente será el que obtenga el cargo. Si las tres variables tienen un valor de 0, entonces no hubo coalición FCPM en ese distrito.

De manera similar, las variables MORENA, PT, y PVEM funcionan para la coalición SHH. Un valor de 1 en alguna de estas variables indica que, si la coalición SHH gana en el distrito, el partido señalado con el 1 será el que obtenga la diputación. Si todas estas variables tienen un valor de 0, significa que no hubo coalición SHH en el distrito.

Finalmente, la variable CI señala si en un distrito hubo candidatos independientes compitiendo por la diputación, asignando un valor de 1 cuando esto ocurrió.

2.2.1 Resumen coaliciones

El siguiente bucle nos permite obtener dos datos clave: primero, el número de distritos donde se acordaron las coaliciones; y segundo, la distribución de los asientos en la Cámara que cada partido de la coalición obtendría si ganara en todos los distritos donde dichas coaliciones fueron pactadas.

# COALICIONES
n <- nrow(COAL_D)
SHH <- rep("SIN COALICION", n)
FCPM <- rep("SIN COALICION", n)
for (i in 1:n) {
  tmp1 <- c("MORENA", "PT", "PVEM")[COAL_D[i,c("MORENA", "PT", "PVEM")] > 0]
  tmp2 <- c("PAN", "PRI", "PRD")[COAL_D[i,c("PAN", "PRI", "PRD")] > 0] 
  if(length(tmp1)){
    SHH[i] <- tmp1
  }
  if(length(tmp2) > 0){
    FCPM[i] <- tmp2
  }
}

La coalición SHH se acordó en 260 distritos, mientras que la coalición FCPM se estableció en 294 distritos. Los acuerdos por partido quedaron de la siguiente manera:

table(SHH)
## SHH
##        MORENA            PT          PVEM SIN COALICION 
##           143            46            71            40
table(FCPM)
## FCPM
##           PAN           PRD           PRI SIN COALICION 
##           113            70           111             6

Por ejemplo, si la coalición SHH ganara en los 260 distritos donde se pactó, los asientos en la Cámara de Diputados se distribuirían de la siguiente forma: MORENA obtendría 143 diputaciones, el PT 46, y el PVEM 71.

Es importante recalcar que estos acuerdos se definen varios meses antes de la elección, y su implementación determina cómo se distribuyen los asientos en caso de que una coalición resulte ganadora.

2.3 Verificación importante

Antes de continuar, es fundamental verificar que la base de datos BD_DIST y los convenios de coalición COAL_D sigan el mismo orden. Esta verificación se puede realizar con el siguiente código:

ID_DF <- paste0(formatC(COAL_D$ID_ESTADO, width = 2, flag = "0"), 
                formatC(COAL_D$ID_DISTRITO, width = 3, flag = "0"))
sum(ID_DF == BD_DIST$ID_DF)
## [1] 300

En este paso, se genera un identificador único utilizando la información de los convenios de coalición y se compara con el identificador correspondiente en la base de datos que contiene la suma de votos a nivel distrito. La comparación verifica que la coincidencia sea exacta, lo cual asegura que ambas bases de datos están perfectamente alineadas: los convenios de coalición del renglón i en la base de datos COAL_D corresponden efectivamente a los votos registrados en el renglón i de la base de datos BD_DIST.

3 ¿Qué dice la Ley?

Para transformar los votos obtenidos en las urnas en asientos en la Cámara de Diputados, es necesario revisar el marco legal correspondiente. En primer lugar, el artículo 52 de la CPEUM (2023) establece que la Cámara de Diputados en México está compuesta por 500 diputados distribuidos de la siguiente manera:

  1. 300 diputados elegidos bajo el principio de mayoría relativa (MR), uno por cada uno de los 300 distritos federales en los que se divide el país.
  2. 200 diputados elegidos bajo el principio de representación proporcional (RP), asignados a través de listas plurinominales.

3.1 Mayoría relativa

3.1.1 Distribución de votos de las combinaciones a cada partido

El primer paso en este principio es distribuir los votos de las combinaciones válidas para votar por la coalición, siguiendo lo establecido en el artículo 311, inciso C, de la (LEGIPE 2023). En este análisis, realizaremos el procedimiento a nivel distrito federal.

Por ejemplo, las formas válidas de votar por la coalición SHH eran:

\[ PT, PVEM, MORENA, PVEM\_PT, PT\_MORENA, PVEM\_MORENA,\ \ \mbox{y}\ \ PVEM\_PT\_MORENA \]

Por esta razón, en la base de datos aparecen las combinaciones PVEM_PT, PT_MORENA, PVEM_MORENA y PVEM_PT_MORENA.

Para calcular los votos en favor de un partido específico, es necesario distribuir los votos de las combinaciones entre los partidos involucrados. Por ejemplo, para el PT, de acuerdo con el artículo 311 mencionado:

\[ PT_0 = PT + \frac{1}{2} PVEM\_PT + \frac{1}{2} PT\_MORENA + \frac{1}{3} PVEM\_PT\_MORENA, \] Un procedimiento similar se aplica a los partidos PVEM y MORENA obteniendo \(PVEM_0\) y \(MORENA_0\).

3.1.2 Resolviendo los decimales

Cuando realizamos la repartición de votos de las combinaciones entre cada partido multiplicando por fracciones, inevitablemente obtenemos resultados con decimales. Además, aunque analíticamente los totales puedan coincidir de manera exacta, al usar una computadora podrían surgir problemas de redondeo. Por lo tanto, los totales calculados a partir de las combinaciones de votos:

\[ TOT = PT + PVEM + MORENA + PVEM\_PT + PT\_MORENA + PVEM\_PT\_MORENA, \]

y

\[ TOT_0 = PT_0 + PVEM_0 + MORENA_0, \]

podrían no coincidir exactamente. Para abordar estas discrepancias, la ley establece que, en caso de fracciones, los votos restantes deben asignarse al partido con mayor votación.

Intentando acatar lo que indica la ley, se siguen los siguientes pasos:

  1. Redondeamos hacia abajo (al entero más cercano pero menor) los valores \(PT_0\), \(PVEM_0\), y \(MORENA_0\), obteniendo \(PT_f\), \(PVEM_f\), y \(MORENA_f\).

  2. Calculamos el nuevo total como: \[ TOT_f = PT_f + PVEM_f + MORENA_f. \] Como claramente \(TOT_f < TOT\), el déficit se define como: \[ \epsilon = TOT - TOT_f, \] un entero positivo que representa los votos que faltan para que las sumas coincidan.

  3. Determinamos el partido con mayor votación entre \(PT_f\), \(PVEM_f\), y \(MORENA_f\). Supongamos que \(MORENA_f\) es el mayor:

    • En ese caso, ajustamos los votos sumando el déficit \(\epsilon\): \[ MORENA_c = MORENA_f + \epsilon, \quad PT_c = PT_f, \quad PVEM_c = PVEM_f. \]

De este modo, garantizamos que:

  1. Los valores ajustados \(MORENA_c\), \(PT_c\), y \(PVEM_c\) sean números enteros.

  2. El total ajustado coincida exactamente con el total original: \[ MORENA_c + PT_c + PVEM_c = TOT. \]

Aunque este procedimiento añade cierta complejidad, asegura que siempre manejemos cantidades enteras y que los totales originales a nivel distrito sean consistentes con los totales ajustados tras repartir los votos de las combinaciones válidas.

Finalmente, los votos correspondientes a las combinaciones de la coalición se eliminan de la base de datos para evitar duplicidades y simplificar el análisis. Este mismo procedimiento se aplica de manera análoga para la coalición FCPM.

A continuación, este algoritmo se implementa en R utilizando funciones sencillas, diseñadas para aplicarse de manera directa y garantizar que los datos sean consistentes y fáciles de trabajar.

# REPARTE TRES (RESOLVIENDO DECIMALES COMO INDICA LA LEY)
reparte_votos_coal_tres_partidos <- function(x, y, z, xy, xz, yz, xyz){
  # SUMA TOTAL: PARA RESOLVER EL PROBLEMA DE LOS DECIMALES
  tot <- x + y + z + xy + xz + yz + xyz
  #
  tmp1 <- 0.5*xy
  x <- x + tmp1
  y <- y + tmp1
  #
  tmp2 <- 0.5*xz
  x <- x + tmp2
  z <- z + tmp2
  #
  tmp3 <- 0.5*yz
  y <- y + tmp3
  z <- z + tmp3
  #
  tmp4 <- 0.3333333*xyz
  x <- x + tmp4
  y <- y + tmp4
  z <- z + tmp4
  # PARA RESOLVER EL PROBLEMA DE LOS DECIMALES
  # OBVIAMENTE SUMANDO 
  # x + y + z != tot, POR LOS DECIMALES
  # REDONDEAMOS HACIA ABAJO
  x1 <- floor(x)
  y1 <- floor(y)
  z1 <- floor(z)
  # SUMA TOTAL SIN DECIMALES:
  tot1 <- x1 + y1 + z1
  # VOTOS FALTANTES PARA QUE LOS TOTALES COINCIDAN 
  eps <- tot - tot1 
  # SEGÚN LA LEY: 
  # EN CASO DE QUE EXISTA UNA FRACCIÓN EN LOS VOTOS RESULTANTES,
  # ESTOS SE ASIGNAN AL PARTIDO CON MAYOR VOTACIÓN. 
  is_x_max <- (x1 > y1) & (x1 > z1)   
  is_y_max <- (y1 > x1) & (y1 > z1)   
  is_z_max <- !(is_x_max | is_y_max)
  # ASIGNANDO REMANENTE AL PARTIDO CON MAYOR VOTACIÓN
  x1 <- x1 + eps*is_x_max
  y1 <- y1 + eps*is_y_max
  z1 <- z1 + eps*is_z_max
  #
  data.frame(x = x1, y = y1, z = z1)
}
diputados_reparte_votos_base <- function(BD){
  FCPM <- reparte_votos_coal_tres_partidos(BD$PAN, BD$PRI, BD$PRD, 
                                           BD$PAN_PRI, BD$PAN_PRD, BD$PRI_PRD, 
                                           BD$PAN_PRI_PRD)
  names(FCPM) <- c("PAN", "PRI", "PRD")
  SHH <- reparte_votos_coal_tres_partidos(BD$PVEM, BD$PT, BD$MORENA, 
                                          BD$PVEM_PT, BD$PVEM_MORENA, BD$PT_MORENA, 
                                          BD$PVEM_PT_MORENA)
  names(SHH) <- c("PVEM", "PT", "MORENA")
  # BASE DE DATOS POR DF CON LOS VOTOS DE CADA PARTIDO DESPUÉS DE REPARTIR VOTOS POR LAS COMBINACIONES VÁLIDAS
  # CANDIDATOS INDEPENDIENTES, CNR Y VN
  cbind(FCPM, SHH, MC = BD$MC, CI = BD$CI,
        CNR = BD$CNR, VN = BD$NULOS, 
        TOTAL = BD$TOTAL, LISTA_NOMINAL = BD$LISTA_NOMINAL)[,c("PAN", "PRI", "PRD", "PVEM", "PT", "MC", "MORENA", 
                                                               "CI", "CNR", "VN", "TOTAL", "LISTA_NOMINAL")]
}
D <- diputados_reparte_votos_base(BD_DIST)
head(D)
##      PAN   PRI  PRD  PVEM    PT    MC MORENA CI CNR    VN  TOTAL LISTA_NOMINAL
## 1  76288 25361 7485  9803  8568 15288  72218  0 137  7178 222326        364676
## 2  73799 10371 5893  7281  5057 20862  65278  0 218  4533 193292        347196
## 3 120511 14465 3473  7950  4868 16793  63665  0 230  9149 241104        385495
## 4  49130  9612 2066  6802  3726 15030  77248  0 153  7249 171016        331719
## 5  34407  8012 1867  8147  5581 14428  85145  0 149  8575 166311        342529
## 6  24186 10545 3362 11088 10034 13802  84747  0 353 10939 169056        334438

Hacemos una verificación rápida para asegurarnos de que las fracciones se resolvieron de manera exacta. Esto lo hacemos comparando la suma total de votos por distrito, incluyendo los votos repartidos, con el total de votos original en la base de datos.

sum(abs(rowSums(D[,1:10]) - D$TOTAL))
## [1] 0

ambos totales coinciden exactamente.

3.1.3 Distribución de diputados por MR

Con la base de datos D y los convenios de coalición, es sencillo determinar los diputados que gana cada partido bajo el principio de MR.

  1. Si en el distrito federal 1 (de 300) hubo una coalición, como la de SHH, se suman los votos de los partidos que la conforman. Si esta suma supera a la de la otra coalición o a la de los partidos que compiten en solitario, el asiento lo obtiene el partido designado en los acuerdos de coalición.

  2. En caso de que no haya coaliciones en el distrito 1, los partidos compiten de manera individual, y el asiento lo gana simplemente el partido con más votos.

Este procedimiento se repite para cada uno de los 299 distritos federales restantes, generando un vector de longitud 300 con los partidos que ganaron en cada distrito.

A partir de este vector, se genera una tabla de frecuencias que muestra el número total de diputados que cada partido obtiene por el principio de MR. Es importante señalar que también pueden existir candidatos independientes que ganen alguna diputación bajo este principio; en este caso, los votos del candidato independiente deben superar tanto a la suma de los votos de cualquier coalición como a los de los partidos en solitario.

A continuación, implementaremos el procedimiento descrito para determinar los diputados que cada partido obtiene por el principio de MR. El objetivo es realizar este cálculo de manera clara, estructurada y eficiente, asegurando que el proceso sea reproducible y los resultados, precisos.

Comenzamos separando los convenios de coalición en los 300 distritos para las dos alianzas: FCPM y SHH. Esto se realiza dividiendo las columnas correspondientes de la base de datos COAL_D:

COAL_D_FCPM <- COAL_D[,c("PAN", "PRI", "PRD")]
COAL_D_SHH <- COAL_D[,c("PVEM", "PT", "MORENA")]

A continuación, identificamos los distritos donde hubo convenios de coalición para cada una de estas alianzas:

hay_fcpm <- rowSums(COAL_D_FCPM) > 0 
hay_shh <- rowSums(COAL_D_SHH) > 0

Ahora trabajaremos con la votación, en este caso extraemos la votación por distrito federal para las fuerzas políticas que compitieron por asientos en la Cámara de Diputados por el principio de MR:

D0 <- D[,1:8]
fuerzas <- names(D0)
fuerzas
## [1] "PAN"    "PRI"    "PRD"    "PVEM"   "PT"     "MC"     "MORENA" "CI"

Finalmente, creamos una variable con los nombres de estas fuerzas políticas para facilitar el análisis posterior.

A continuación hacemos la repartición, aquí se muestra el código.

MR_VECTOR <- rep(NA, 300)
for (i in 1:300) {
  if (hay_fcpm[i]) {
    convenio_fcpm <- c("PAN", "PRI", "PRD")[COAL_D_FCPM[i, ] > 0]
    D0[i, convenio_fcpm] <- sum(D0[i, c("PAN", "PRI", "PRD")])
  }
  if (hay_shh[i]) {
    convenio_shh <- c("PVEM", "PT", "MORENA")[COAL_D_SHH[i, ] > 0]
    D0[i, convenio_shh] <- sum(D0[i, c("PVEM", "PT", "MORENA")])
  }
  MR_VECTOR[i] <- fuerzas[which.max(D0[i, ])]
}
MR_VECTOR <- factor(MR_VECTOR, levels = fuerzas)
MR <- table(MR_VECTOR)
MR
## MR_VECTOR
##    PAN    PRI    PRD   PVEM     PT     MC MORENA     CI 
##     32      9      1     57     38      1    161      1

El procedimiento anterior sigue estos pasos:

  1. Para cada distrito (de los 300), verificamos si hubo un convenio de coalición para FCPM o SHH:

    • Si hubo un convenio para FCPM, identificamos el partido al que se asigna la coalición (según los acuerdos) y sumamos los votos de los partidos que conforman FCPM. Este total se asigna al partido del convenio.
    • Si hubo un convenio para SHH, realizamos el mismo procedimiento, pero considerando los partidos de SHH.
  2. En cada distrito, determinamos el partido con el mayor número de votos después de aplicar los convenios de coalición.

  3. Los resultados se almacenan en un vector llamado MR_VECTOR, que contiene el partido ganador para cada uno de los 300 distritos.

  4. Finalmente, generamos una tabla de frecuencias que muestra el número total de diputados que cada partido obtiene bajo este principio.

3.1.4 Un ejercicio alternativo puramente académico: asignar el asiento al partido con más votos de la coalición

¿Qué pasaría si en lugar de seguir los convenios de coalición, asignáramos el asiento al partido que obtuvo más votos dentro de la coalición? Este es un interesante ejercicio académico que nos permite explorar una alternativa al procedimiento original.

Para ello, seguimos este procedimiento:

  1. Creamos una copia de la base de datos, D0_MAX, para preservar los datos originales.

  2. Iteramos sobre los 300 distritos. Si existe un convenio de coalición:

    • Para la coalición FCPM, identificamos el partido con más votos (entre PAN, PRI, y PRD) y le asignamos la suma de los votos de toda la coalición.
    • Para la coalición SHH, realizamos el mismo procedimiento considerando PVEM, PT, y MORENA.
  3. Después de asignar los votos en cada distrito, determinamos el partido con más votos en el distrito correspondiente.

  4. Finalmente, generamos una tabla que muestra la composición de la Cámara bajo esta lógica.

El código para implementar este procedimiento es el siguiente:

D0_MAX <- D[,1:8]
MR_VECTOR_MAX <- rep(NA, 300)
for (i in 1:300) {
  if(hay_fcpm[i]){
    max_fcpm <- c("PAN", "PRI", "PRD")[which.max(D0_MAX[i, c("PAN", "PRI", "PRD")])]
    D0_MAX[i, max_fcpm] <- sum(D0_MAX[i, c("PAN", "PRI", "PRD")])
  }
  if(hay_shh[i]){
    max_shh <- c("PVEM", "PT", "MORENA")[which.max(D0_MAX[i, c("PVEM", "PT", "MORENA")])]
    D0_MAX[i, max_shh] <- sum(D0_MAX[i, c("PVEM", "PT", "MORENA")])
  }
  MR_VECTOR_MAX[i] <- fuerzas[which.max(D0_MAX[i,])]
}
MR_VECTOR_MAX <- factor(MR_VECTOR_MAX, levels = fuerzas)
MR_MAX <- table(MR_VECTOR_MAX)
MR_MAX
## MR_VECTOR_MAX
##    PAN    PRI    PRD   PVEM     PT     MC MORENA     CI 
##     35      7      0      6      0      1    250      1

Para comparar ambos enfoques, creamos una tabla que muestra la distribución de diputados obtenida por cada partido bajo el procedimiento original y el alternativo (asignar el asiento al partido con más votos dentro de la coalición). A continuación, presentamos los resultados:

# Crear una matriz con los resultados de ambos enfoques
comparacion <- cbind(Original = MR, Alternativo = MR_MAX)

# Mostrar la tabla de comparación
comparacion <- cbind(Original = MR, Alternativo = MR_MAX)

tabla <- knitr::kable(comparacion, 
                      caption = "Comparación de la composición de la Cámara de Diputados por MR vía cada enfoque")
kableExtra::kable_styling(tabla, 
                          bootstrap_options = c("striped", "hover", "condensed"), 
                          full_width = FALSE, 
                          position = "center")
Comparación de la composición de la Cámara de Diputados por MR vía cada enfoque
Original Alternativo
PAN 32 35
PRI 9 7
PRD 1 0
PVEM 57 6
PT 38 0
MC 1 1
MORENA 161 250
CI 1 1

La principal diferencia en número de asientos entre ambos enfoques radica en la concentración de los escaños. Bajo el método basado en convenios, partidos como PVEM y PT logran una representación significativa con 57 y 38 diputaciones, respectivamente, mientras que en el enfoque alternativo estos pierden completamente sus escaños, y MORENA pasa de 161 a 250. De manera similar, en FCPM, PAN aumenta ligeramente su representación, mientras que PRI y PRD ven reducidos o eliminados sus escaños. Esto evidencia que el enfoque alternativo tiende a concentrar el poder en los partidos dominantes dentro de cada coalición.

Es importante notar la diferencia entre los dos enfoques presentados. En el caso de los convenios, los partidos políticos deciden con meses de antelación cómo se distribuirán los escaños en caso de que una coalición gane. Obviamente estos acuerdo no necesariamente refleja las preferencias individuales de los votantes dentro de la coalición, sino que obedece a estrategias políticas entre los partidos.

Por otro lado, el enfoque alternativo, donde el escaño se asigna al partido con más votos dentro de la coalición, refleja de manera más directa la voluntad expresada por los ciudadanos en las urnas. Este enfoque toma en cuenta qué partido fue más favorecido por los votantes, sin considerar los acuerdos previos entre los partidos políticos.

3.2 Representación proporcional

El principio de reparto proporcional, parecería muy sencillo sin embargo es imprescindible revisar la ley para entender que esta percepción es equivocada.

3.2.1 Tipos de votaciones y primera repartición

Es esencial comprender las distintas votaciones que establece la ley (artículo 15 de la (LEGIPE 2023)):

  1. Votación Total Emitida (VTE): Incluye todos los votos registrados en las casillas.

  2. Votación Válida Emitida (VVE): Resulta de descontar de la VTE los votos anulados y los emitidos a favor de candidatos no registrados. Cabe mencionar que esta categoría sí considera los votos destinados a candidatos independientes.

  3. Votación Nacional Emitida (VNE): Se calcula a partir de la VVE, excluyendo los votos a favor de candidatos independientes y de partidos que no alcanzaron al menos el 3% de la VVE.

Estos conceptos son fundamentales para la asignación de los 200 diputados por RP, donde la VNE es la base para la primera distribución. Sin embargo, como se observa, el punto de partida inicial siempre es la VTE, como se ilustra en la tabla siguiente:

VTE <- colSums(D)[-12]
VVE <- VTE
VVE[9:11] <- 0
VVE[11] <- sum(VVE)
TOT <- data.frame(VTE = VTE, VVE = VVE)
p_VVE <- TOT$VVE/TOT$VVE[11]
TOT$p_VVE <- 100*p_VVE
TOT$VNE <- 0
TOT$VNE[p_VVE >= 0.03] <- TOT$VVE[p_VVE >= 0.03]
TOT$VNE[11] <- 0
TOT$VNE[11] <- sum(TOT$VNE)
p_VNE <- TOT$VNE/TOT$VNE[11]
TOT$p_VNE <- 100*p_VNE
TOT$RP_0 <- 200*p_VNE
TOT
##             VTE      VVE       p_VVE      VNE      p_VNE      RP_0
## PAN    10049375 10049375  17.5604655 10049375  18.040180  36.08036
## PRI     6623712  6623712  11.5743980  6623712  11.890586  23.78117
## PRD     1449744  1449744   2.5333097        0   0.000000   0.00000
## PVEM    4993874  4993874   8.7263887  4993874   8.964775  17.92955
## PT      3254753  3254753   5.6874162  3254753   5.842784  11.68557
## MC      6497404  6497404  11.3536851  6497404  11.663844  23.32769
## MORENA 24286396 24286396  42.4385018 24286396  43.597831  87.19566
## CI        72012    72012   0.1258351        0   0.000000   0.00000
## CNR       49329        0   0.0000000        0   0.000000   0.00000
## VN      2189869        0   0.0000000        0   0.000000   0.00000
## TOTAL  59466468 57227270 100.0000000 55705514 100.000000 200.00000

A partir de la matriz D construida previamente, se obtiene la VTE sumando los votos en las columnas, excluyendo la lista nominal que no es relevante aquí. La VVE se calcula eliminando de la VTE los votos nulos y los correspondientes a candidatos no registrados, generando un nuevo total.

Posteriormente, se calculan los porcentajes de la VVE con respecto a su total, los cuales sirven para determinar la VNE. Esta última incluye únicamente a los partidos que superan el 3% de los votos válidos y excluye los votos de candidatos independientes.

Finalmente, se calcula el total de la VNE, sus porcentajes relativos, y en una primera iteración se reparten los 200 diputados por RP considerando estos porcentajes. Sin embargo, nuevamente enfrentamos un problema de redondeo. Para garantizar que los valores sean enteros y que la suma de los diputados sea exactamente 200, la ley establece el uso de la técnica del resto mayor. A continuación, se muestra una función en R que implementa una estrategia análoga.

redondea_bien <- function(nh0, n){
  nh1 <- floor(nh0)
  n1 <- sum(nh1) 
  eps <- nh0 - nh1
  o <- order(eps, decreasing = TRUE)
  d <- n - n1
  nh <- nh1
  nh[o][1:d] <- nh1[o][1:d] + 1
  nh
}
TOT$RP_1 <- c(redondea_bien(TOT$RP_0[1:7], 200), c(0, 0, 0, 200))
TOT
##             VTE      VVE       p_VVE      VNE      p_VNE      RP_0 RP_1
## PAN    10049375 10049375  17.5604655 10049375  18.040180  36.08036   36
## PRI     6623712  6623712  11.5743980  6623712  11.890586  23.78117   24
## PRD     1449744  1449744   2.5333097        0   0.000000   0.00000    0
## PVEM    4993874  4993874   8.7263887  4993874   8.964775  17.92955   18
## PT      3254753  3254753   5.6874162  3254753   5.842784  11.68557   12
## MC      6497404  6497404  11.3536851  6497404  11.663844  23.32769   23
## MORENA 24286396 24286396  42.4385018 24286396  43.597831  87.19566   87
## CI        72012    72012   0.1258351        0   0.000000   0.00000    0
## CNR       49329        0   0.0000000        0   0.000000   0.00000    0
## VN      2189869        0   0.0000000        0   0.000000   0.00000    0
## TOTAL  59466468 57227270 100.0000000 55705514 100.000000 200.00000  200

3.2.2 Sobre-representación

La sobrerrepresentación en la Cámara de Diputados ocurre cuando la proporción de curules que ocupa un partido político excede significativamente su porcentaje de apoyo electoral a nivel nacional. Esto puede distorsionar la relación entre la voluntad de los votantes y la composición legislativa. Para limitar esta situación, el artículo 15 de la (LEGIPE 2023) establece dos restricciones:

  1. En ningún caso, un partido político podrá contar con un número de diputados por ambos principios que representen un porcentaje del total de la Cámara que exceda en 8 puntos a su porcentaje de VNE. Esta base no se aplicará al partido político que, por sus triunfos en distritos uninominales, obtenga un porcentaje de curules del total de la Cámara, superior a la suma del porcentaje de su votación nacional emitida más el 8%.

  2. Ningún partido puede tener más de 300 asientos en total, sumando los obtenidos por MR y RP.

En términos matemáticos, ambas restricciones pueden ser homologadas y condensadas en la siguiente cota:

\[ \text{COTA} = \min\left\{300, \left\lfloor 500 \left( \textbf{VNE} \% + 8\% \right) \right\rfloor \right\}, \]

la cual define el número máximo de diputados que un partido puede obtener bajo ambos principios, MR + RP.

COTA <- pmin(300, floor(500*(p_VNE + 0.08)))
COTA[8:11] <- 0
MR <- c(MR, 0, 0, 300)
P1 <- data.frame(RP_1 = TOT$RP_1, MR = MR, 
                 REP_1 = TOT$RP_1 + MR,  COTA = round(COTA), 
                 row.names = row.names(TOT))
P1
##        RP_1  MR REP_1 COTA
## PAN      36  32    68  130
## PRI      24   9    33   99
## PRD       0   1     1   40
## PVEM     18  57    75   84
## PT       12  38    50   69
## MC       23   1    24   98
## MORENA   87 161   248  257
## CI        0   1     1    0
## CNR       0   0     0    0
## VN        0   0     0    0
## TOTAL   200 300   500    0

Como se aprecia, en ningún caso el número de diputados obtenido por la primera repartición por RP más los que ya se tenían por MR supera la cota. Entonces, esta primera repartición sería definitiva.

3.2.3 Sobre-representación: ejercicio alternativo puramete académico

Volviendo al ejercicio planteado en la sección 3.1.4, en donde en lugar de considerar los convenios de coalción la diputación por MR la obtiene el partido de la coalción con mayor número de votos, se tendría lo siguiente.

MR3 <- c(MR_MAX, 0, 0, 300)
P2 <- data.frame(RP1 = TOT$RP_1, MR = MR3, 
                 REP_1 = TOT$RP_1 + MR3,  COTA = round(COTA), 
                 row.names = row.names(TOT))
P2
##        RP1  MR REP_1 COTA
## PAN     36  35    71  130
## PRI     24   7    31   99
## PRD      0   0     0   40
## PVEM    18   6    24   84
## PT      12   0    12   69
## MC      23   1    24   98
## MORENA  87 250   337  257
## CI       0   1     1    0
## CNR      0   0     0    0
## VN       0   0     0    0
## TOTAL  200 300   500    0

En este escenario ficticio, MORENA supera la COTA de sobre-representación por 80 asientos. Por ello, se aplica lo establecido en el artículo 18 de la (LEGIPE 2023):

  • El exceso se corrige ajustando la representación de MORENA al límite máximo permitido en RP, quedando con solo 7 asientos por este principio. Este partido quedaría excluido del proceso de asignación restante. Es importante destacar que, según el artículo 15-3, los ajustes solo afectan la RP, mientras que los asientos obtenidos por MR permanecen intactos.

  • Se redefine la Votación Nacional Efectiva (VNEF), excluyendo al partido que rebasó la COTA.

  • Los diputados restantes (193 = 200 - 7, ya que a MORENA se le asignan los 7 correspondientes a su máximo) se distribuyen proporcionalmente utilizando la VNEF y aplicando la técnica del resto mayor para resolver problemas de redondeo y garantizar una distribución equitativa.

TOT2 <- data.frame(VNE = TOT$VNE, VNEF = TOT$VNE, 
                   row.names = row.names(TOT))
TOT2$VNEF[7] <- 0
TOT2$VNEF[11] <- sum(TOT2$VNEF[-11])
p_VNEF <- TOT2$VNEF/TOT2$VNEF[11]
TOT2$p_VNEF <- 100*p_VNEF
RP_MORENA <- P2$RP1[7] - (P2$REP_1[7] - P2$COTA[7])
d <- 200 - RP_MORENA
TOT2$RP_2 <-  c(redondea_bien(d*p_VNEF[1:7], d), c(0, 0, 0, 200))
TOT2$RP_2[7] <- RP_MORENA
TOT2$MR_MAX <- c(MR_MAX, 0, 0, 300)
TOT2$REP_2 <- TOT2$RP_2 + TOT2$MR_MAX
TOT2$COTA <- COTA
TOT2
##             VNE     VNEF    p_VNEF RP_2 MR_MAX REP_2 COTA
## PAN    10049375 10049375  31.98490   62     35    97  130
## PRI     6623712  6623712  21.08179   41      7    48   99
## PRD           0        0   0.00000    0      0     0   40
## PVEM    4993874  4993874  15.89438   30      6    36   84
## PT      3254753  3254753  10.35915   20      0    20   69
## MC      6497404  6497404  20.67978   40      1    41   98
## MORENA 24286396        0   0.00000    7    250   257  257
## CI            0        0   0.00000    0      1     1    0
## CNR           0        0   0.00000    0      0     0    0
## VN            0        0   0.00000    0      0     0    0
## TOTAL  55705514 31419118 100.00000  200    300   500    0

Con este ajuste todos los partidos satisfacel la COTA

# Crear una matriz con los resultados de ambos enfoques
comparacion2 <- data.frame(Original = P1$REP_1, 
                           Alternativo = TOT2$REP_2, COTA = TOT2$COTA, 
                   row.names = row.names(TOT2))

tabla2 <- knitr::kable(comparacion2, 
                      caption = "Comparación de la composición de la Cámara de Diputados por MR + RP vía cada enfoque")
kableExtra::kable_styling(tabla2, 
                          bootstrap_options = c("striped", "hover", "condensed"), 
                          full_width = FALSE, 
                          position = "center")
Comparación de la composición de la Cámara de Diputados por MR + RP vía cada enfoque
Original Alternativo COTA
PAN 68 97 130
PRI 33 48 99
PRD 1 0 40
PVEM 75 36 84
PT 50 20 69
MC 24 41 98
MORENA 248 257 257
CI 1 1 0
CNR 0 0 0
VN 0 0 0
TOTAL 500 500 0

Para apreciar la diferencia entre ambos enfoques, calculamos el número de diputados obtenidos por cada coalición. Con el enfoque original, la coalición SHH obtuvo 373 asientos, mientras que con el enfoque alternativo alcanzaría solo 313. Por otro lado, la coalición FCPM obtuvo 102 asientos con el enfoque original, mientras que con el enfoque alternativo serían 145.

Estos resultados sugieren que los convenios de la coalición SHH fueron una estrategia partidista eficaz para maximizar el número de asientos obtenidos por los partidos que la conforman.

Referencias

CPEUM. 2023. «Constitución Política de los Estados Unidos Mexicanos, Compendio de Legislación Nacional Electoral Tomo I». INE. https://ine.mx/compendio-normativo/.
LEGIPE. 2023. «Ley General de Instituciones y Procedimientos Electorales, Compendio de Legislación Nacional Electoral Tomo II». INE. https://ine.mx/compendio-normativo/.
LGPP. 2023. «Ley General de Partidos Políticos, Compendio de Legislación Nacional Electoral Tomo II». INE. https://ine.mx/compendio-normativo/.