Analizando los telegramas de las PASO 2017
Como sabrán, la cámara electoral nos pone a disposición un sitio Web con una API muy copada para poder analizar los resultados de la votación y encontrar anomalías. Bueno, en realidad no. Pero, por lo menos los datos están en HTML sin demasiada complejidad.
Como hacemos para encontrar casos como este, obviamente incorrectos, en la base de telegramas, sin una API o un export de la base de datos?
Bueno, podemos ir al maravilloso mundo de los scrapers, con Python y Scrapy, se come, se educa y... Bueno quizás estoy exagerando pero anda muy bien. No los voy a aburrir con los detalles, el scraper se conecta a http://resultados.gob.ar/99/resu/content/telegramas/Itelegramas.htm, se baja todo a json y lo hace en aprox 1-2h con una conexión de 100mb.
El scraper esta en https://github.com/sicarul/resultados_elecciones2017_scraper y la ultima bajada a json que hice esta en http://elecciones.sicarul.com/resultados_08_14_2017T22_27.json.gz
Y ahora, ¿como analizamos este monstruo de 95166 mesas?
En mi caso, me gusta trabajar el análisis de datos con el excelente software estadístico R, con su interfaz mas popular, el R Studio.
Así que cargamos los datos en dos tablas, mesas
y votos
, el primero tiene una fila por cada mesa, y el segundo una fila por cada combinacion de mesa, partido y lista, indicando cuantos votaron en esta mesa por esa lista del partido.
provincia | seccion | circuito | mesa | estado | impugnados | nulos_concejales | nulos_senadores_nacionales | nulos_senadores_provinciales | nulos_diputados_nacionales | nulos_diputados_provinciales | blanco_concejales | blanco_senadores_nacionales | blanco_senadores_provinciales | blanco_diputados_nacionales | blanco_diputados_provinciales | recurridos_concejales | recurridos_senadores_nacionales | recurridos_senadores_provinciales | recurridos_diputados_nacionales | recurridos_diputados_provinciales | mesa_id | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | Buenos Aires | Adolfo Alsina | 0001 | 00001 | Grabada | 0 | 0 | 0 | 0 | 0 | 25 | 26 | 31 | 36 | 0 | 0 | 0 | 0 | 1 | |||
2 | Buenos Aires | Adolfo Alsina | 0001 | 00002 | Grabada | 0 | 8 | 8 | 8 | 8 | 12 | 3 | 11 | 13 | 0 | 0 | 0 | 0 | 2 | |||
3 | Buenos Aires | Adolfo Alsina | 0001 | 00003 | Grabada | 0 | 0 | 0 | 0 | 0 | 18 | 16 | 25 | 29 | 0 | 0 | 0 | 0 | 3 | |||
4 | Buenos Aires | Adolfo Alsina | 0001 | 00004 | Grabada | 0 | 2 | 4 | 4 | 2 | 19 | 14 | 17 | 25 | 0 | 0 | 0 | 0 | 4 | |||
5 | Buenos Aires | Adolfo Alsina | 0001 | 00005 | Grabada | 0 | 0 | 0 | 0 | 0 | 24 | 20 | 29 | 33 | 1 | 1 | 1 | 1 | 5 |
Cuando el tipo de votos no aplica para la mesa, y se cargo asi en el sistema, dejamos las columnas en nulo (NA en R), asi las podemos diferenciar de "0 votos".
Por otro lado, cargamos la tabla votos
:
provincia | seccion | circuito | mesa | estado | partido | lista | diputados_nacionales | diputados_provinciales | senadores_nacionales | senadores_provinciales | concejales | mesa_id | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | Santa Fe | San Martín | 0169 | 07900 | Grabada | FEDERAL | DIGNIDAD CIUDADANA | 0 | 91134 | ||||
2 | Santa Fe | San Martín | 0169 | 07900 | Grabada | FEDERAL | RECREO SOCIAL | 0 | 91134 | ||||
3 | Santa Fe | San Martín | 0169 | 07900 | Grabada | NACIONALISTA CONSTITUCIONAL - UNIR | UNION PARA RENOVAR SANTA FE | 0 | 91134 | ||||
4 | Santa Fe | San Martín | 0169 | 07900 | Grabada | UNION CELESTE Y BLANCO | UNIDOS POR SANTA FE | 1 | 91134 | ||||
5 | Santa Fe | San Martín | 0169 | 07900 | Grabada | MOVIMIENTO INDEPENDIENTE RENOVADOR | DESARROLLO AGRO INDUSTRIAL | 0 | 91134 |
Aclaracion: La mesa_id
es solo un id inventado en la transformacion de datos que es unico por combinacion de provincia+seccion+circuito+mesa, ya que los numeros de mesa se pueden repetir en distintos circuitos.
Para simplificar el análisis, decidi solo analizar los diputados nacionales, que es el denominador mas comun por lo que vi.
Teniendo todos estos datos cargados, lo primero que vi es que hay mesas con muy pocos votos, como estos:
Tambien hay mesas con estado "Incidencia definitiva", estas mesas son las que entiendo no se cargaron porque el data entry de INDRA decidio que no se podia resolver (Los que estuve viendo suelen ser telegramas ilegibles o vacios) ejemplo:
Las incidencias las filtro porque no tiene sentido analizarlas, aunque si puede servir contarlas, 847 de las 95166 mesas que descarge vinieron con incidencias, un 0.89%.
Tambien excluyo las mesas mayor o igual a 09001, ya que estas son mesas de extranjeros y no pueden votar por cargos nacionales, solo locales, por lo cual no tiene sentido al analizar diputados nacionales.
Las mesas con menos de 20 votos las identifico y las separo del análisis, considerando que es injusto comparar los porcentajes con mesas con cerca de 300 votantes. Así encuentro mesas anomalas como estas (En total son 307):
Provincia | Seccion | Circuito | Mesa | Total de votos a diputados nacionales | |
---|---|---|---|---|---|
1 | Chaco | Libertad | 0035 | 01050 | 2 |
2 | Santa Fe | San Lorenzo | 0417 | 07365 | 7 |
3 | Buenos Aires | Hipólito Yrigoyen | 0742A | 00024 | 15 |
4 | Mendoza | Santa Rosa | 0101A | 03466 | 9 |
5 | Córdoba | Tulumba | 0362 | 08332 | 9 |
6 | Buenos Aires | Trenque Lauquén | 0960 | 00099 | 14 |
7 | Entre Ríos | San Salvador | 0315 | 03252 | 6 |
8 | Entre Ríos | Colón | 0281 | 02972 | 18 |
9 | Santa Fe | Nueve de Julio | 0286 | 03716 | 15 |
10 | Córdoba | Cruz del Eje | 0053 | 04182 | 5 |
Luego, ya sacando todas esas anomalías, no estoy seguro de que es un circuito, al hacer este análisis supuse que los circuitos son zonas donde las mesas están geograficamente cercanas entre si, dentro de la seccion, si esta suposicion es incorrecta habria que reconsiderar como hacer el análisis. Teniendo en cuenta esta suposicion, calcule para cada circuito cual es la banda de "normalidad" de votos a cada partido, sin importar la lista para suavizar un poco los resultados.
Estableci un parametro midiendo por cada circuito, cual es el promedio que recibe de votos ese partido por mesa en porcentaje, y el desvio estandar, para entender que variacion es razonable. Por lo que vi (Un poco a ojo) en general se comporta como una distribucion normal. Como detectar anomalías con esto? Decidi que una mesa con 3 desvios estandares por arriba o por abajo del promedio es anomalo y debe ser revisado. Así encontre mesas como esta, donde los numeros están pero en el lugar incorrecto, y el telegrama se cargo con estado "Grabada"
Me parece increible que no capturen estas anomalías con un simple control que cualquiera con un minimo de suspicacia podria implementar.
Revisando las anomalías agrupadas por partido y provincia, podemos ver que los que mas veces están "por debajo de lo esperado" son mesas de Cambiemos y Unidad ciudadana, seguidos por 1PAIS, PJ, IAF y FIT, los que están agrupados en OTROS suman mas que todos esos juntos, pero son demasiados partidos para visualizar comodamente. Pareceria que los votos que faltan en esos partidos, no se compensan con mesas donde "sobren", pareceria que los votos que faltan están en los "OTROS" partidos.
Sin embargo viendo los casos que vi hasta ahora, no necesariamente sea fraude sino probablemente simple incompetencia al cargar los datos o formular las actas. Haciendo "Zoom" en los OTROS que tienen mas votos que los esperados encontramos estos:
Desconozco si esto es por fraude, error en carga, un análisis malo de mi parte, etc. Pero ceo que valdria la pana revisar las mesas anomalas, las que revise hasta ahora siempre tienen algo raro.
El proyecto en github para ejecutar estos análisis en R y poder continuarlos es https://github.com/sicarul/resultados_elecciones2017_analyze