librairie jugmenet_majoritaire python locale

- pour préparer une comparaison avec https://github.com/MieuxVoter/majority-judgment-library-python
This commit is contained in:
philippe lhardy
2025-07-03 11:00:15 +02:00
parent ff11eb0a71
commit 2694ca7165
4 changed files with 188 additions and 118 deletions

View File

@@ -1,5 +1,14 @@
# Libraire de calcul Jugement majoritaire
## Etude
Une étude de l'existant est dans le répertoire étude.
Ce projet est plutot un jouet comparé à l'existant.
L'idée ici serait d'avoir une API commune ou à minima des formats d'échanges communs.
## Cette Librairie
Le fonctionnement actuel est de fournir un fichier json contenant la votation.
Ce fichier n'a pas de connaissance des votants, juste de leur vote.

View File

@@ -0,0 +1,104 @@
import json
import sys
verbose=False
def collect_votes(votes,candidats,mentions,warnings):
collect={}
default_mention=mentions-1
for vote in votes:
# missing candidat in vote picks the worse one
for candidat in candidats:
if not candidat in vote:
vote[candidat]=default_mention
for candidat,mention in vote.items():
if mention > default_mention or mention < 0:
mention = default_mention
warnings.append("index de mention invalide, soit la liste des mentions est erronnée soit la mention dans le vote est erronée")
if candidat in collect:
if mention in collect[candidat]:
collect[candidat][mention]=collect[candidat][mention]+1
else:
collect[candidat][mention]=1
else:
collect[candidat]={mention:1}
return collect
def jugement_majoritaire(poll):
votants=poll['votants']['decompte']
candidats=poll['candidats']
nombre_candidats=len(candidats)
# l'ordre des mentions est de la meilleure à la pire (reject)
nom_mentions=poll['mentions']
mentions=len(nom_mentions)
votes=poll["votation"]["votes"]
if verbose:
print('candidats:' + str(candidats))
print(votes)
warnings=[]
collect=collect_votes(votes,list(candidats),mentions,warnings)
if verbose:
print(collect)
votant_median_check= votants / 2 if votants % 2 == 0 else ((votants-1) / 2) +1
votant_median=votants // 2 + votants % 2
if votant_median_check != votant_median:
print('[ERROR] le nombre median de votants semble erroné. contactez le developpeur de ce code.' + str(votant_median_check))
merite={}
mention_mediane={}
merite_pourcent={}
# cumul : du meilleur au pire
# range_mentions = range(len(mentions))
# cumul du pire au meilleur
range_mentions = range(mentions-1,-1,-1)
for candidat in list(candidats):
vote=collect[candidat]
cumul=0
m=[0 for i in range(mentions)]
mention_m=None
pourcent=[0 for i in range(mentions)]
for mention in range_mentions:
if mention in vote:
cumul=cumul+vote[mention]
pourcent[mention]= ( 100 * vote[mention] ) / votants
if cumul >= votant_median and mention_m is None:
mention_m=mention
m[mention]=cumul
if cumul < votants:
print('[ERROR] le cumul des votes doit correspondre au nombre de votants. contactez le developpeur de ce code.')
mention_mediane[candidat]=mention_m
merite[candidat]=m
merite_pourcent[candidat]=pourcent
if verbose:
print(merite)
print(mention_mediane)
# les gagnants sont ceux qui ont la mention mediane minimale ( la meilleure )
found=[]
for mention in range(0,mentions):
for candidat,merite_median in mention_mediane.items():
if merite_median == mention:
found.append({candidat:candidats[candidat]})
if len(found) > 0:
break
if verbose:
print(found)
print(nom_mentions[mention])
result = {'resultat':{'mention':nom_mentions[mention],'candidats':found},'merite':merite,'profil':merite_pourcent,"warnings":warnings}
return result

View File

@@ -1,5 +1,6 @@
import json
import sys
from jugement_majoritaire import jugement_majoritaire
if len(sys.argv) > 1:
poll_file=sys.argv[1]
@@ -15,101 +16,6 @@ with open(poll_file,'r') as poll_fd:
if verbose:
print(poll)
votants=poll['votants']['decompte']
candidats=poll['candidats']
nombre_candidats=len(candidats)
# l'ordre des mentions est de la meilleure à la pire (reject)
nom_mentions=poll['mentions']
mentions=len(nom_mentions)
default_mention=mentions-1
votes=poll["votation"]["votes"]
if verbose:
print('candidats:' + str(candidats))
print(votes)
warnings=[]
default_vote={}
for candidat in candidats:
default_vote[candidat]=default_mention
collect={}
for vote in votes:
# missing candidat in vote picks the worse one
for candidat in candidats:
if not candidat in vote:
vote[candidat]=default_mention
for candidat,mention in vote.items():
if mention > default_mention or mention < 0:
mention = default_mention
warnings.append("index de mention invalide, soit la liste des mentions est erronnée soit la mention dans le vote est erronée")
if candidat in collect:
if mention in collect[candidat]:
collect[candidat][mention]=collect[candidat][mention]+1
else:
collect[candidat][mention]=1
else:
collect[candidat]={mention:1}
if verbose:
print(collect)
votant_median_check= votants / 2 if votants % 2 == 0 else ((votants-1) / 2) +1
votant_median=votants // 2 + votants % 2
if votant_median_check != votant_median:
print('[ERROR] le nombre median de votants semble erroné. contactez le developpeur de ce code.' + str(votant_median_check))
merite={}
mention_mediane={}
merite_pourcent={}
# cumul : du meilleur au pire
# range_mentions = range(len(mentions))
# cumul du pire au meilleur
range_mentions = range(mentions-1,-1,-1)
for candidat in candidats:
vote=collect[candidat]
cumul=0
m=[0 for i in range(mentions)]
mention_m=None
pourcent=[0 for i in range(mentions)]
for mention in range_mentions:
if mention in vote:
cumul=cumul+vote[mention]
pourcent[mention]= ( 100 * vote[mention] ) / votants
if cumul >= votant_median and mention_m is None:
mention_m=mention
m[mention]=cumul
if cumul < votants:
print('[ERROR] le cumul des votes doit correspondre au nombre de votants. contactez le developpeur de ce code.')
mention_mediane[candidat]=mention_m
merite[candidat]=m
merite_pourcent[candidat]=pourcent
if verbose:
print(merite)
print(mention_mediane)
# les gagnants sont ceux qui ont la mention mediane minimale ( la meilleure )
found=[]
for mention in range(0,mentions):
for candidat,merite_median in mention_mediane.items():
if merite_median == mention:
found.append({candidat:candidats[candidat]})
if len(found) > 0:
break
if verbose:
print(found)
print(nom_mentions[mention])
result = {'resultat':{'mention':nom_mentions[mention],'candidats':found},'merite':merite,'profil':merite_pourcent,"warnings":warnings}
result = jugement_majoritaire(poll)
print(json.dumps(result))

View File

@@ -22,15 +22,85 @@ https://en.wikipedia.org/wiki/Jugement_majoritaire
|source|info|interet|
|------------------|-----------------------------|-------------|
|https://github.com/AlexJade23/JugementMajoritaire|RAS VIDE|1/20|
|https://github.com/ostix360/JugementMajoritaire|Où est l'algo ?|2/20|
|https://github.com/MieuxVoter/mieuxvoter.fr||18/20|
|https://github.com/CitoyensDeDemain/JugementMajoritaire|Il y a un algo, mais pas de format de donnée, données hardcodées / API et pas de procédure d'install|11/20|
|https://github.com/ostix360/JugementMajoritaire|Où est l'algo ?|2/20|
|https://github.com/AlexJade23/JugementMajoritaire|RAS VIDE|1/20|
|
# https://mieuxvoter.fr/en
C'est la référence, les théoriciens du vote majoritaire ont été invités à participer à l'élaboration de ce site.
Par contre pour trouver la librairie de base...
https://github.com/MieuxVoter/mieuxvoter.fr
image docker
https://app.mieuxvoter.fr/en/votes/ult-kxm-vzcr
https://app.mieuxvoter.fr/en/results/ult-kxm-vzcr
https://app.mieuxvoter.fr/en/admin/ult-kxm-vzcr/eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhZG1pbiI6dHJ1ZSwiZWxlY3Rpb24iOiJ1bHRreG12emNyIn0.TzkM380pk0eVo8_iHJGYANxlapVbp5Z3jxLQSzqLpRM
https://app.mieuxvoter.fr/fr/votes/ult-kxm-vzcr : même en français 'Very good' ...
Obligation de noter tous les participants.
## Librairie python
https://github.com/MieuxVoter/majority-judgment-library-python
Très courte ( ./majority_judgment/__init__.py 145 lignes )
```
>>> from majority_judgment import majority_judgment
>>> data = {
... 'Pizza': [!, 0, 3, 0, 2, 0, 3, 1, 2, 3],
... 'Chips': [0, 1, 0, 2, 1, 2, 2, 3, 2, 3],
... 'Pasta': [0, 1, 0, 1, 2, 1, 3, 2, 3, 3],
... 'Bread': [0, 1, 2, 1, 1, 2, 1, 2, 2, 3],
... }
>>> majority_judgment(data, reverse=False)
{'Chips': 0, 'Pasta': 1, 'Pizza': 2, 'Bread': 3}
```
(!) ?
## API REST python
https://github.com/MieuxVoter/majority-judgment-api-python
License: GNU aGPLV3 / CECILL variant affero compliant
|postgres||
|python| >= 3.11 |
serveur uvicorn
```
uvicorn app.main:app --reload --env-file .env.local
```
profiles :
|core| if you only need the backend and database|
|dashboard| if you only need Metabase|
|image| if you only need to store images|
|backup| for restic|
Election Candidat Grade Vote
# david chavalarias
https://github.com/davidchavalarias/jugement-majoritaire
Dans le cadre d'une soutenance en 2014 le porjet n'a pas été maintenu ni forké.
Dans le cadre d'une soutenance en 2014 le projet n'a pas été maintenu ni forké.
Une application sous symfony2 ( php Doctrine )
@@ -443,22 +513,3 @@ langage for smart contracts : blockchain donc.
# https://github.com/jeromeschwaederle/Vote_Jugement_Majoritaire
python simple
# https://mieuxvoter.fr/en
https://github.com/MieuxVoter/mieuxvoter.fr
image docker
https://app.mieuxvoter.fr/en/votes/ult-kxm-vzcr
https://app.mieuxvoter.fr/en/results/ult-kxm-vzcr
https://app.mieuxvoter.fr/en/admin/ult-kxm-vzcr/eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhZG1pbiI6dHJ1ZSwiZWxlY3Rpb24iOiJ1bHRreG12emNyIn0.TzkM380pk0eVo8_iHJGYANxlapVbp5Z3jxLQSzqLpRM
https://app.mieuxvoter.fr/fr/votes/ult-kxm-vzcr : même en français 'Very good' ...
Obligation de noter tous les participants.