python-vote-core
python-vote-core copied to clipboard
weighted voting
I introduced a function for weighted voting with a St. Lagüe weight function given by 1/(1+2(n-1)) http://www.uv.es/~pla/sistelec/propabga.htm
ponderado.py: from abstract_classes import MultipleWinnerVotingSystem from common_functions import matching_keys import types import copy
class ponderado(MultipleWinnerVotingSystem):
def __init__(self, ballots, tie_breaker=None, required_winners=1):
super(Ponderado, self).__init__(ballots, tie_breaker=tie_breaker, required_winners=required_winners)
def calculate_results(self):
# Standardize the ballot format and extract the candidates
self.candidates = set()
for ballot in self.ballots:
# Convert single candidate ballots into ballot lists
if not isinstance(ballot["ballot"], types.ListType):
ballot["ballot"] = [ballot["ballot"]]
# Ensure no ballot has an excess of votes
if len(ballot["ballot"]) > self.required_winners:
raise Exception("A ballot contained too many candidates")
# Add all candidates on the ballot to the set
self.candidates.update(set(ballot["ballot"]))
# Sum up all votes for each candidate with weight!!
self.tallies = dict.fromkeys(self.candidates, 0)
for ballot in self.ballots:
for icand in range(0,len(ballot["ballot"])):
candidate = ballot["ballot"][icand]
peso = 1./(1+2*icand)
self.tallies[candidate] += ballot["count"]*peso
tallies = copy.deepcopy(self.tallies)
# Determine which candidates win
winning_candidates = set()
while len(winning_candidates) < self.required_winners:
# Find the remaining candidates with the most votes
largest_tally = max(tallies.values())
top_candidates = matching_keys(tallies, largest_tally)
# Reduce the found candidates if there are too many
if len(top_candidates | winning_candidates) > self.required_winners:
self.tied_winners = top_candidates.copy()
while len(top_candidates | winning_candidates) > self.required_winners:
top_candidates.remove(self.break_ties(top_candidates, True))
# Move the top candidates into the winning pile
winning_candidates |= top_candidates
for candidate in top_candidates:
del tallies[candidate]
self.winners = winning_candidates
def as_dict(self):
data = super(Ponderado, self).as_dict()
data["tallies"] = self.tallies
return data
Perhaps, it could be added to this suggested new method a selector for different weighting functions. For instance the above included St. Lague weighting function given by 1/(1+2(n-1)) as default and another extra option like a Hont based weighting function 1/(1+n-1)=1/n
Where n is the position on the preferential vote from n=1 for the first selection to the last one