Skip to content

Instantly share code, notes, and snippets.

@ofaurax
Created March 25, 2026 23:56
Show Gist options
  • Select an option

  • Save ofaurax/f3903c7817d78c87a93bb6f0f52c151d to your computer and use it in GitHub Desktop.

Select an option

Save ofaurax/f3903c7817d78c87a93bb6f0f52c151d to your computer and use it in GitHub Desktop.
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"id": "446c78b0",
"metadata": {},
"source": [
"# Estimation du report des voix St Max 1er vers 2nd tour\n",
"\n",
"## Méthodologie\n",
"* On a 15 bureaux différents, qui ont chacun des scores différents\n",
"* On a les scores du 1er tour (Garello=G1, Molina=M1, etc. y compris nuls-nlancs et abstention)\n",
"* On a les scores du second tour Garello (G2), Molina (M2), les nuls-blancs et l'abstention regroupés en A2\n",
"* On différencie le vote Decanis D1, du reste des autres listes R1\n",
"* On cherche à trouver la fonction F(score 1er tour) = score 2nd tour\n",
"\n",
"## Hypothèses\n",
"* On considère que Garello et Molina ont gardé leurs électeurs, c'est-à-dire `G2 = G1 + ...` et `M2 = M1 + ...`\n",
"* D1 se reporte dans G2 (D1G2), M2 (D1M2) et dans A2 (D1A2) de manière linéaire: D1G2 est une fraction fixe de D1.\n",
"* R1 idem. On considère R1 comme une grandeur homogène comme étant les votants non-Garello, non-RN, non-Decanis.\n",
"* `G2 = G1 + D1 * D1G2 + R1 * R1G2`, idem pour M2 avec D1M2 et R1G2\n",
"* Si on a D1G2 et D1M2, on en déduit D1A2 puisque la somme des 3 fait 1 (100%)\n",
"* On connaît G1 et G2 pour 15 bureaux, l'objectif est de trouver D1G2 et R1G2 qui minimise l'erreur entre le G2 calculé (G2c) et le G2 connu"
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "906e0024",
"metadata": {},
"outputs": [],
"source": [
"# G1[n] correspond au bureau n, on met la G1[n] à 0\n",
"G1 = [0, 172, 216, 170, 201, 227, 155, 183, 188, 148, 227, 204, 177, 166, 215, 222]\n",
"D1 = [0, 106, 96,55,83,89,88,87,89,77,88,83,80,79,100,88]\n",
"R1 = [0, 153, 143,114,148,148,108,145,116,134,154,178,138,110,148,143]\n",
"G2 = [0, 291, 358,265,367,350,247,294,275,254,341,355,301,305,358,347]"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "be000e2b",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
" 0% 90% -35.0\n",
" 10% 80% 44.2\n",
" 20% 80% -84.6\n",
" 30% 70% -5.4\n",
" 40% 60% 73.8\n",
" 50% 60% -55.0\n",
" 60% 50% 24.2\n",
" 80% 40% -25.4\n",
" 90% 30% 53.8\n",
" 100% 30% -75.0\n"
]
}
],
"source": [
"for d1g2 in range(11): # 1 .. 10 => 10% .. 100%\n",
" for r1g2 in range(11):\n",
" diff = 0.0\n",
" for bureau in range(1, 16):\n",
" g2c = G1[bureau] + D1[bureau] * d1g2/10 + R1[bureau] * r1g2/10\n",
" d = G2[bureau] - g2c\n",
" diff += d\n",
" if diff < 100 and diff > -100:\n",
" print(\"{:4}% {:4}% {:7.7}\".format(d1g2*10, r1g2*10, diff))"
]
},
{
"cell_type": "markdown",
"id": "c86d2f30",
"metadata": {},
"source": [
"On voit que pour minimiser la différence, chaque baisse de la part de D1 doit être compensé par la part de R1.\n",
"On fait le même calcul pour Molina"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "8efddef1",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
" 0% 60% -5.0\n",
" 10% 50% 74.2\n",
" 20% 50% -54.6\n",
" 30% 40% 24.6\n",
" 50% 30% -25.0\n",
" 60% 20% 54.2\n",
" 70% 20% -74.6\n",
" 80% 10% 4.6\n",
" 90% 0% 83.8\n",
" 100% 0% -45.0\n"
]
}
],
"source": [
"M1 = [0, 151, 152,134,208,205,158,219,169,142,215,266,158,155,212,185]\n",
"M2 = [0,262,251,180,262,296,263,308,255,222,305,339,244,205,294,286]\n",
"for d1m2 in range(11):\n",
" for r1m2 in range(11):\n",
" diff = 0.0\n",
" for bureau in range(1, 16):\n",
" m2c = M1[bureau] + D1[bureau] * d1m2/10 + R1[bureau] * r1m2/10\n",
" d = M2[bureau] - m2c\n",
" diff += d\n",
" if diff < 100 and diff > -100:\n",
" print(\"{:4}% {:4}% {:7.7}\".format(d1m2*10, r1m2*10, diff))"
]
},
{
"cell_type": "markdown",
"id": "0a9e05fc",
"metadata": {},
"source": [
"On sait que `d1g2 + d1m2 + d1a2 = 100` (idem `r1*`), donc on peut faire varier d1a2 et utiliser `d1m2 = 100 - d1g2 - d1a2` pour calculer la diff globale des 2 boucles, et idem pour `r1*`.\n",
"Comme la participation est presque la même et que les nuls-blancs augmentent de seulement 2%, on néglige la fuite vers l'absentation, d'où `d1a2 = 0% ou 10%`"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "bf86db3d",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"De Decanis Réserve Score\n",
"vers Gar Abs Mol | Gar Abs Mol | (meilleur qd petit)\n",
" 0% 10% 90% | 80% 10% 10% | 392.4\n",
" 0% 0% 100% | 90% 10% 0% | 377.8\n",
" 0% 10% 90% | 90% 0% 10% | 397.0\n",
" 10% 0% 90% | 80% 10% 10% | 371.4\n",
" 10% 10% 80% | 80% 10% 10% | 375.4\n",
" 20% 10% 70% | 70% 10% 20% | 377.8\n",
" 30% 0% 70% | 70% 10% 20% | 376.2\n"
]
}
],
"source": [
"print(\"De {:18} {:18} {}\".format(\"Decanis\", \"Réserve\", \"Score\"))\n",
"print(\"vers {:4} {:4} {:4} | {:4} {:4} {:4}| {}\".format(\"Gar\", \"Abs\", \"Mol\",\"Gar\", \"Abs\", \"Mol\", \"(meilleur qd petit)\"))\n",
"for d1g2 in range(11): # 1 .. 10 => 10% .. 100%\n",
" for r1g2 in range(11):\n",
" for d1a2 in range(2):\n",
" d1m2 = 10 - d1g2 - d1a2\n",
" if d1m2 < 0:\n",
" continue\n",
" for r1a2 in range(2):\n",
" r1m2 = 10 - r1g2 - r1a2\n",
" if r1m2 < 0:\n",
" continue\n",
" diff = 0.0\n",
" for bureau in range(1, 16):\n",
" g2c = G1[bureau] + D1[bureau] * d1g2/10 + R1[bureau] * r1g2/10\n",
" d = G2[bureau] - g2c\n",
" diff += abs(d)\n",
" m2c = M1[bureau] + D1[bureau] * d1m2/10 + R1[bureau] * r1m2/10\n",
" d = M2[bureau] - m2c\n",
" diff += abs(d)\n",
" if diff < 400:\n",
" print(\" {:4}% {:4}% {:4}% | {:4}% {:4}% {:4}% | {:7.7}\".format(\n",
" d1g2*10, d1a2*10, d1m2*10, r1g2*10, r1a2*10, r1m2*10, diff))"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "d9eeca84",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.18"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment