Métodos de Análisis
Resumen General
Sección titulada «Resumen General»El pipeline del Observatorio del Congreso ejecuta seis módulos de análisis que transforman datos brutos de votación nominal en información sobre estructura política y poder. La cadena de procesamiento va desde registros individuales de voto hasta posiciones ideológicas, redes de co-votación, particiones en comunidades, rankings de centralidad e índices de poder formal vs. empírico.
| Módulo | Entrada | Salida | Algoritmo Central |
|---|---|---|---|
| W-NOMINATE | Matriz de votos (legisladores x eventos) | Coordenadas de puntos ideales | SVD + Newton-Raphson |
| Co-Votación | Registros de votación | Matriz NxN de similitud + grafo | Conteo de acuerdos |
| Comunidades | Grafo de co-votación | Partición (nodo -> comunidad) | Modularidad de Louvain |
| Centralidad | Grafo de co-votación | Puntuaciones por nodo | Grado ponderado, intermediación |
| Índices de Poder | Escaños por partido | Valores Shapley-Shubik, Banzhaf | Enumeración combinatoria |
| Poder Empírico | Registros de votación + escaños | Frecuencias de partidos críticos | Análisis de votaciones nominales |
W-NOMINATE: Estimación de Puntos Ideales
Sección titulada «W-NOMINATE: Estimación de Puntos Ideales»W-NOMINATE (Weighted Nominal Three-Step Estimation) es el algoritmo estándar para estimar posiciones ideológicas de legisladores a partir de votaciones nominales, desarrollado por Poole & Rosenthal (1985, 1997).
Referencias:
- Poole & Rosenthal (1985). “A Spatial Model for Legislative Roll Call Analysis”. American Journal of Political Science, 29(2), 357-384.
- Poole & Rosenthal (1997). Congress: A Political-Economic History of Roll Call Voting. Oxford University Press.
- Poole (2005). Spatial Models of Parliamentary Voting. Cambridge University Press.
Funcionamiento
Sección titulada «Funcionamiento»El algoritmo recibe una matriz binaria de votos y recupera los puntos ideales de los legisladores en un espacio de políticas de baja dimensionalidad.
Paso 1: Binarización. Los strings de voto se mapean a valores binarios:
| Tipo de voto | Valor binario |
|---|---|
a_favor | 1 (Yea) |
en_contra | 0 (Nay) |
abstencion | NaN (excluido) |
ausente | NaN (excluido) |
Paso 2: Filtrado. Se eliminan votos con baja información y legisladores inactivos:
min_votes = 10 # mínimo de votos binarios por legisladormin_participants = 10 # mínimo de participantes binarios por evento de votolopsided_threshold = 0.975 # filtrar votos casi unánimesPaso 3: Estimación. El algoritmo estima dos parámetros por legislador (coordenadas en espacio 2D) y dos por evento de voto:
- Puntos ideales (x_i, y_i): la posición de cada legislador en el espacio de políticas
- Pesos de relevancia (beta): qué tan abruptamente cae la utilidad de un legislador al alejarse del plano de corte
- Vectores normales (w_j): definen el plano de corte que separa Yea de Nay para cada voto
La inicialización usa descomposición SVD de la matriz binaria, seguida de optimización Newton-Raphson que maximiza la verosimilitud de clasificación.
Métricas de Calidad
Sección titulada «Métricas de Calidad»| Métrica | Descripción | Interpretación |
|---|---|---|
| Tasa de clasificación | % de votos correctamente predichos por el modelo | Mayor = mejor ajuste; rango típico 85-95% |
| APRE | Aggregate Proportional Reduction in Error | Mejora sobre el baseline (predicción por mayoría); 0.0 = sin mejora, 1.0 = perfecto |
Variantes de Implementación
Sección titulada «Variantes de Implementación»nominate_by_legislatura: ejecuta W-NOMINATE por separado para cada legislatura, produciendo espacios ideales independientes por periodonominate_cross_legislatura: combina todas las legislaturas en una sola ejecución, ubicando a todos los legisladores en un espacio compartido para comparación directa
Dependencias
Sección titulada «Dependencias»scipy (svd, minimize, norm), numpy, pandas
Análisis de Co-Votación
Sección titulada «Análisis de Co-Votación»La co-votación mide la frecuencia con la que cada par de legisladores vota de la misma manera. Es la base para todo el análisis basado en redes.
Pipeline de Construcción
Sección titulada «Pipeline de Construcción»- Carga de datos: votos, personas y organizaciones desde SQLite
- Normalización de partidos:
normalize_party()mapea valores mixtos devote.groupa IDs canónicos de organización - Asignación de partido primario:
get_primary_party()asigna cada legislador a su partido más frecuente - Construcción de matriz:
build_covotacion_matrix()produce una matriz numpy NxN donde la entrada (i,j) = conteo de acuerdos entre legisladores i y j, normalizado a 0-1 - Construcción de grafo:
build_graph()convierte la matriz en un grafo NetworkX con:- Nodos: legisladores, con atributos de partido y género
- Aristas: pares de co-votación, con
weight= similitud normalizada
# Cálculo simplificado del peso de co-votaciónfor i, j in legislator_pairs: shared_votes = votes_i.intersection(votes_j) total_votes = votes_i.union(votes_j) weight = len(shared_votes) / len(total_votes)El módulo retorna un diccionario que contiene:
| Clave | Tipo | Descripción |
|---|---|---|
matrix | arreglo numpy NxN | Similitud de co-votación por pares |
graph | networkx.Graph | Red de co-votación ponderada |
party_map | dict | mapeo person_id -> partido |
org_map | dict | mapeo org_id -> nombre del partido |
persons_df | DataFrame | Metadatos de legisladores |
Detección de Comunidades (Louvain)
Sección titulada «Detección de Comunidades (Louvain)»El algoritmo de Louvain detecta comunidades de legisladores que votan de forma similar, yendo más allá de las etiquetas formales de partido para revelar bloques de votación reales.
Algoritmo
Sección titulada «Algoritmo»Louvain realiza optimización iterativa en dos fases:
- Movimiento local: cada nodo se mueve a la comunidad vecina que produce la mayor ganancia de modularidad
- Agregación: las comunidades se colapsan en super-nodos y el proceso se repite
El parámetro de resolución controla la granularidad de las comunidades:
| Resolución | Efecto |
|---|---|
| < 1.0 | Menos comunidades, más grandes (más grueso) |
| 1.0 (default) | Modularidad estándar |
| > 1.0 | Más comunidades, más pequeñas (más fino) |
detect_communities() retorna un diccionario de partición que mapea cada node_id a un community_id.
analyze_communities() produce un análisis detallado por comunidad:
- Composición partidista: conteo y porcentaje de cada partido dentro de la comunidad
- Métrica de pureza: porcentaje del partido dominante (100% = bloque puro de partido)
- Legisladores cruzados: individuos cuya comunidad difiere de su partido formal
- Sub-bloques: detección de facciones internas dentro de partidos grandes (específicamente sub-bloques de MORENA)
Dependencias
Sección titulada «Dependencias»python-louvain (paquete community), networkx
Métricas de Centralidad
Sección titulada «Métricas de Centralidad»La centralidad identifica legisladores estructuralmente importantes en la red de co-votación. Se utilizan dos métricas complementarias.
Centralidad de Grado Ponderada
Sección titulada «Centralidad de Grado Ponderada»centrality[node] = weighted_degree(node) / max_weighted_degreeEl grado ponderado de cada nodo es la suma de sus pesos de arista (intensidad total de co-votación con todos los demás legisladores), normalizado por el grado ponderado máximo en el grafo. Los valores van de 0.0 a 1.0.
Interpretación: grado ponderado alto = el legislador co-vota intensamente con muchos otros, indicando alineación con la coalición dominante.
Centralidad de Intermediación (Betweenness)
Sección titulada «Centralidad de Intermediación (Betweenness)»betweenness = nx.betweenness_centrality(graph, weight=None)La intermediación se calcula sin ponderar (weight=None). Esta es una decisión deliberada:
Interpretación: intermediación alta = el legislador se ubica en los caminos más cortos entre comunidades distintas, actuando como potencial intermediario o legislador bisagra.
| Métrica | Manejo de pesos | Captura |
|---|---|---|
| Grado Ponderado | Usa pesos | Intensidad general de co-votación |
| Intermediación | Ignora pesos (weight=None) | Posición estructural de puente |
Índices de Poder (Nominal)
Sección titulada «Índices de Poder (Nominal)»Los índices de poder nominal calculan el poder de negociación de cada partido basándose únicamente en el conteo de escaños, asumiendo que todos los miembros votan con su partido.
Índice de Shapley-Shubik
Sección titulada «Índice de Shapley-Shubik»Para un partido p, el índice de Shapley-Shubik promedia el poder marginal a través de todas las N! permutaciones de partidos:
for permutation in all_permutations(parties): coalition = set() for party in permutation: coalition.add(party) if coalition alcanza mayoría AND coalition - {party} no: party recibe un punto "pivot" break # repetir para todas las N! permutacionesss_index[party] = pivots[party] / factorial(N)Un partido es crítico (un pivot) en la posición k de una permutación si la coalición de los primeros k partidos alcanza la mayoría, pero eliminar ese partido la deja por debajo.
Índice de Banzhaf
Sección titulada «Índice de Banzhaf»Para un partido p, se cuentan todas las coaliciones ganadoras donde p es crítico (su defección cambia el resultado):
for coalition in all_subsets(parties): if coalition es ganadora AND coalition - {party} es perdedora: party es crítico en esta coaliciónbanzhaf_index[party] = critical_count[party] / total_critical_countAsignación de Escaños
Sección titulada «Asignación de Escaños»La multi-pertenencia (legisladores que pertenecen a más de un partido a lo largo de su carrera) se resuelve mediante:
- Recopilar todas las membresías de partido para cada legislador
- Asignar al partido donde el legislador emitió más votos
- Empates se resuelven con la membresía con
start_datemás reciente
Análisis por Cámara
Sección titulada «Análisis por Cámara»Ambos índices soportan análisis separado para Diputados (camara='D') y Senado (camara='S').
Análisis de Poder Empírico
Sección titulada «Análisis de Poder Empírico»El poder nominal asume disciplina partidista. El poder empírico mide lo que realmente ocurre en las votaciones nominales.
Partidos Críticos por Votación
Sección titulada «Partidos Críticos por Votación»Para cada evento de votación, el módulo identifica qué partidos fueron necesarios para alcanzar el umbral de mayoría:
winning_coalition = partidos que votaron con la mayoríafor party in winning_coalition: seats_without = majority_seats - party_seats if seats_without < majority_threshold: party es "crítico" para esta votaciónÍndice de Poder Empírico
Sección titulada «Índice de Poder Empírico»empirical_power[party] = times_critical[party] / total_vote_eventsEsto produce una puntuación de 0.0 a 1.0 que refleja qué tan frecuentemente los votos de un partido fueron realmente decisivos.
Legisladores Bisagra y Votaciones Cerradas
Sección titulada «Legisladores Bisagra y Votaciones Cerradas»El módulo identifica:
- Votaciones cerradas: eventos donde el margen fue estrecho (cerca del umbral de mayoría)
- Legisladores bisagra (swing voters): legisladores individuales cuyo voto podría haber cambiado el resultado
- Principales disidentes: legisladores que votaron en contra de la línea de su partido con mayor frecuencia, clasificados por conteo de disidencias
Comparación de Poder
Sección titulada «Comparación de Poder»La salida clave es una comparación de cuatro dimensiones:
| Índice | Base | Qué Mide |
|---|---|---|
| Nominal (escaños) | Conteo de escaños | Representación formal |
| Shapley-Shubik | Distribución de escaños | Poder de negociación (basado en permutaciones) |
| Banzhaf | Distribución de escaños | Poder de negociación (basado en coaliciones) |
| Empírico | Votos reales | Relevancia en la práctica |
Las divergencias entre poder nominal y empírico revelan partidos formalmente pequeños pero estratégicamente críticos (o viceversa).
Dinámica Temporal
Sección titulada «Dinámica Temporal»Todos los métodos soportan análisis temporal a través de legislaturas.
Análisis por Legislatura
Sección titulada «Análisis por Legislatura»Cada legislatura recibe su propio análisis independiente:
- Espacios ideales W-NOMINATE separados
- Grafos de co-votación y detección de comunidades independientes
- Índices de poder específicos por cámara que reflejan cambios en escaños
Comparación entre Legislaturas
Sección titulada «Comparación entre Legislaturas»nominate_cross_legislaturaubica a todos los legisladores en un espacio ideal compartido, permitiendo comparación directa entre periodos- Seguimiento de evolución de comunidades: qué legisladores cambian de comunidad entre legislaturas, y qué implica eso sobre realineamiento de coaliciones
Tendencias de Modularidad
Sección titulada «Tendencias de Modularidad»El seguimiento del puntaje de modularidad de Louvain a través de legislaturas revela cambios en la cohesión de los bloques de votación:
- Modularidad creciente: los partidos votan de forma más cohesiva, divisiones partidistas más marcadas
- Modularidad decreciente: aumenta la votación cruzada, los bloques se disuelven o realinean
- Caídas súbitas: pueden indicar un evento legislativo importante (votación de reforma, cambio de liderazgo) que interrumpió los patrones normales de votación